日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

最长不下降子序列问题

發布時間:2024/10/5 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 最长不下降子序列问题 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

https://www.luogu.org/problemnew/show/P2766

題解:網絡流+最大流+DP

首先動態規劃求出F[i],表示以第i位為開頭的最長上升序列的長度,求出最長上升序列長度K。

1、把序列每位i拆成兩個點<i.a>和<i.b>,從<i.a>到<i.b>連接一條容量為1的有向邊。

2、建立附加源S和匯T,如果序列第i位有F[i]=K,從S到<i.a>連接一條容量為1的有向邊。

3、如果F[i]=1,從<i.b>到T連接一條容量為1的有向邊。

4、如果j>i且A[i] < A[j]且F[j]+1=F[i],從<i.b>到<j.a>連接一條容量為1的有向邊。

求網絡最大流,就是第二問的結果。把邊(<1.a>,<1.b>)(<N.a>,<N.b>)(S,<1.a>)(<N.b>,T)這四條邊的容量修改為無窮大,再求一次網絡最大流,就是第三問結果。

上述建模方法是應用了一種分層圖的思想,把圖每個頂點i按照F[i]的不同分為了若干層,這樣圖中從S出發到T的任何一條路徑都是一個滿足條件的最長上升子序列。

由于序列中每個點要不可重復地取出,需要把每個點拆分成兩個點。單位網絡的最大流就是增廣路的條數,所以最大流量就是第二問結果。

第三問特殊地要求x1和xn可以重復使用,只需取消這兩個點相關邊的流量限制,求網絡最大流即可。

/* *@Author: STZG *@Language: C++ */ #include <bits/stdc++.h> #include<iostream> #include<algorithm> #include<cstdlib> #include<cstring> #include<cstdio> #include<string> #include<vector> #include<bitset> #include<queue> #include<deque> #include<stack> #include<cmath> #include<list> #include<map> #include<set> //#define DEBUG #define RI register int #define endl "\n" using namespace std; typedef long long ll; //typedef __int128 lll; const int N=1000+10; const int M=100000+10; const int MOD=1e9+7; const double PI = acos(-1.0); const double EXP = 1E-8; const int INF = 0x3f3f3f3f; int s,t,n,m,k,p,l,r,u,v; int ans,cnt,flag,temp,sum,maxflow,len; int a[N]; int dis[N]; int dp[N]; struct node{int u,v;ll c;node(){};node(int u,int v,ll cap):u(u),v(v),c(cap){} }; vector<node>edge; vector<int>G[N]; void Addedge(int u,int v,ll cap){edge.push_back({u,v,cap});edge.push_back({v,u,0});int sz=edge.size();G[u].push_back(sz-2);G[v].push_back(sz-1); } bool bfs(int u){memset(dis,-1,sizeof(dis));dis[u]=0;queue<int>q;q.push(u);while(!q.empty()){int u=q.front();q.pop();for(int i=0,j=G[u].size();i<j;i++){node e=edge[G[u][i]];if(dis[e.v]<0&&e.c>0){dis[e.v]=dis[u]+1;q.push(e.v);}}}return dis[t]>0; } ll dfs(int u,ll flow){if(u==t){return flow;}ll now;for(int i=0,j=G[u].size();i<j;i++){node e=edge[G[u][i]];if(e.c>0&&dis[e.v]==dis[u]+1&&(now=dfs(e.v,min(flow,e.c)))){edge[G[u][i]].c-=now;edge[G[u][i]^1].c+=now;return now;}}return 0; } void dinic(){ll res;while(bfs(s)){while((res=dfs(s,INF))){ans+=res;}} } void init(){s=0;t=2*n+1;edge.clear();for(int i=s;i<=t;i++)G[i].clear();ans=0;maxflow=0;len=0; } int main() { #ifdef DEBUGfreopen("input.in", "r", stdin);//freopen("output.out", "w", stdout); #endif//ios::sync_with_stdio(false);//cin.tie(0);//cout.tie(0);//scanf("%d",&t);//while(t--){while(~scanf("%d",&n)){for(int i=1;i<=n;i++){scanf("%d",&a[i]);dp[i]=1;}init();for(int i=1;i<=n;i++)for(int j=1;j<i;j++)if(a[j]<=a[i])dp[i]=max(dp[i],dp[j]+1);for(int i=1;i<=n;i++)len=max(len,dp[i]);cout<<len<<endl;for(int i=1;i<=n;i++)if(dp[i]==1)Addedge(s,i,1);for(int i=1;i<=n;i++)if(dp[i]==len)Addedge(i+n,t,1);for(int i=1;i<=n;i++)Addedge(i,i+n,1);for(int i=1;i<=n;i++)for(int j=1;j<i;j++)if(a[j]<=a[i]&&dp[j]+1==dp[i])Addedge(j+n,i,1);dinic();cout<<ans<<endl;Addedge(1,1+n,INF);Addedge(s,1,INF);if(dp[n]==len)Addedge(n,n*2,INF),Addedge(n*2,t,INF);dinic();cout<<ans<<endl;}//}#ifdef DEBUGprintf("Time cost : %lf s\n",(double)clock()/CLOCKS_PER_SEC); #endif//cout << "Hello world!" << endl;return 0; }

?

與50位技術專家面對面20年技術見證,附贈技術全景圖

總結

以上是生活随笔為你收集整理的最长不下降子序列问题的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。