网络流24题最长递增子序列
Posted 蒟蒻ZJO :-)
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了网络流24题最长递增子序列相关的知识,希望对你有一定的参考价值。
Description
给定正整数序列x1,..., xn。
(1)计算其最长递增子序列的长度s。
(2)计算从给定的序列中最多可取出多少个长度为s的递增子序列。
(3)如果允许在取出的序列中多次使用x1和xn,则从给定序列中最多可取出多少个长度为s的递增子序列。
设计有效算法完成(1)(2)(3)提出的计算任务
Input
第1 行有1个正整数n(n<=500),表示给定序列的长度。
接下来的1 行有n个正整数x1,..., xn。
Output
第1 行是最长递增子序列的长度s。
第2行是可取出的长度为s 的递增子序列个数。
第3行是允许在取出的序列中多次使用x1和xn时可取出的长度为s 的递增子序列个数。
Sample Input
4
3 6 2 5
Sample Output
2
2
3
一开始自己想了个很鬼的模型30分,后来分析完全是错的。
我那个模型并没有求最大流,只是在残余网络上找路径,所以不能保证答案是最大的。
先DP求出以每个点的为起点的最长不下降序列长度,以为f[i];
注意是最长不下降,这题题面与数据不符合(坑了我1个小时)
将一个点一分为二,分为A部和B部。
Ai和Bi连一条容量为1的边。
若f[i]==MAX S->Ai,若f[i]==1 Bi->T。
枚举i后面的j,若a[i]<=a[j] 且f[j]+1==f[i],
连Bi->Aj。
然后跑最大流。
第三问是一样的,只是把S和T连1和n还有A1连B1的边,An连Bn的边容量改为INF。
1 #include<set> 2 #include<map> 3 #include<queue> 4 #include<stack> 5 #include<ctime> 6 #include<cmath> 7 #include<string> 8 #include<vector> 9 #include<cstdio> 10 #include<cstdlib> 11 #include<cstring> 12 #include<iostream> 13 #include<algorithm> 14 using namespace std; 15 struct data{ 16 int nex,to,w; 17 }e[530000],g[530000]; 18 int head[1010],edge=-1,a[510],lev[1010],f[510],n; 19 void add(int from,int to,int w){ 20 g[++edge].nex=head[from]; 21 g[edge].w=w; 22 g[edge].to=to; 23 head[from]=edge; 24 } 25 bool bfs(int s,int t){ 26 memset(lev,0,sizeof(lev)); 27 queue<int>q; 28 q.push(s);lev[s]=1; 29 while(!q.empty()){ 30 int u=q.front(); 31 q.pop(); 32 for(int i=head[u];i!=-1;i=e[i].nex) 33 if(!lev[e[i].to] && e[i].w>0){ 34 lev[e[i].to]=lev[u]+1; 35 q.push(e[i].to); 36 if(e[i].to==t)return 1; 37 } 38 } 39 return 0; 40 } 41 int dfs(int s,int t,int k){ 42 if(s==t) return k; 43 int tag=0; 44 for(int i=head[s];i!=-1;i=e[i].nex) 45 if(e[i].w>0 && lev[e[i].to]==lev[s]+1){ 46 int d=dfs(e[i].to,t,min(k-tag,e[i].w)); 47 e[i].w-=d; 48 e[i^1].w+=d; 49 tag+=d; 50 if(tag==k) return tag; 51 } 52 return tag; 53 } 54 void dinic(int s,int t){ 55 int flow=0; 56 while(bfs(s,t)) flow+=dfs(s,t,1999999999); 57 printf("%d\n",flow); 58 } 59 int zd=0; 60 void DP(){ 61 for(int i=1;i<=n;i++) 62 f[i]=1; 63 for(int i=n;i>=1;i--) 64 for(int j=i+1;j<=n;j++) 65 if(a[j]>=a[i]) f[i]=max(f[i],f[j]+1); 66 for(int i=1;i<=n;i++) 67 zd=max(zd,f[i]); 68 printf("%d\n",zd); 69 } 70 int main() 71 { 72 freopen("!.in","r",stdin); 73 freopen("!.out","w",stdout); 74 memset(head,-1,sizeof(head)); 75 bool f1=0,f2=0; 76 scanf("%d",&n); 77 int s=0,t=2*n+1; 78 for(int i=1;i<=n;i++) 79 scanf("%d",&a[i]); 80 DP(); 81 if(zd==1) {printf("%d\n%d\n",n,n);return 0;} 82 for(int i=1;i<=n;i++) add(i,i+n,1),add(i+n,i,0); 83 for(int i=1;i<=n;i++){ 84 if(f[i]==zd){if(i==1) f1=1;add(s,i,1),add(i,s,0);} 85 if(f[i]==1) {if(i==n) f2=1;add(i+n,t,1),add(t,i+n,0);} 86 } 87 for(int i=1;i<=n;i++) 88 for(int j=i+1;j<=n;j++) 89 if(a[j]>=a[i] && f[j]+1==f[i]) add(i+n,j,1),add(j,i+n,0); 90 memcpy(e,g,sizeof(e)); 91 dinic(s,t); 92 if(f1) add(s,1,1999999999),add(1,s,0); 93 if(f2) add(2*n,t,1999999999),add(t,2*n,0); 94 add(1,n+1,1999999999),add(n+1,1,0); 95 add(n,2*n,1999999999),add(2*n,n,0); 96 memcpy(e,g,sizeof(e)); 97 dinic(s,t); 98 return 0; 99 }
以上是关于网络流24题最长递增子序列的主要内容,如果未能解决你的问题,请参考以下文章