hdu 3998 Sequence -最长下升子序列+最大流
hdu 3998 Sequence --最长上升子序列+最大流
/* 题意:给出一个序列,问该序列的最长上升子序列的长度是多少,以及相同长度的,组成元素完全不同的最长上升子序列的个数。 思路:第一问用O(n^2)的dp求解,第二问就是最多不相交路径了。 设最长上升子序列的长度为k,第一问解决后,dp数组中保存的是以这个数结尾的最长上升子序列的长度,于是把每个数拆成两个点i和i’,中间连容量为1的边,表示每个数只能选一次, dp值为1的与源点连边,dp值为k的与汇点连边,容量均为无穷, 然后枚举所有的i和j(j<i),如满足dp[j]+1==dp[i]且a[j]<a[i],则从j’向i连一条容量无穷的边,然后求最大流即可。 另外此题由于数据规模较小,可以采用求出最长升序列后,枚举删除最长升序列的做法,如此重复多次,也可求得结果,复杂度O(n^3)。 */ #include<stdio.h> #include<string.h> #define inf 0x7fffffff int data[100010],dp[100010]; int n,m; struct edge//边 { int u,v,f,next,b,c;//边的 前节点 后节点 可用流 下条边的编号 原来边上流的上下界 }e[1000000]; int head[1000000],s,t,yong,ind,sum; int d[1000000],num[1000000]; int min(int a,int b){return a<b?a:b;} int pro() { int ret=0,i,j,k; memset(dp,0,sizeof(dp)); dp[0]=1; for(i=1;i<n;i++) { k=-1; for(j=0;j<i;j++) { if(data[j]<data[i]&&(k==-1||dp[k]<dp[j])) k=j; } if(k!=-1) dp[i]=dp[k]+1; else dp[i]=1; if(dp[i]>ret) ret=dp[i]; } return ret;//返回值居然写成了dp[n-1] 很长时间没有写代码 生疏了 } void adde(int u,int v,int f) { e[yong].f=f,e[yong].u=u,e[yong].v=v; e[yong].next=head[u],head[u]=yong++; e[yong].f=0,e[yong].u=v,e[yong].v=u; e[yong].next=head[v],head[v]=yong++; } void build() { int i,j; yong=0; memset(head,-1,sizeof(head)); //2n点 0--2n-1 s=2n,t=2n+1; s=2*n,t=2*n+1; for(i=0;i<n;i++) adde(2*i,2*i^1,1); for(i=0;i<n;i++) { if(dp[i]==1) adde(s,2*i,inf); if(dp[i]==m) adde(2*i^1,t,inf); } for(i=0;i<n;i++) { if(dp[i]<m) { for(j=i+1;j<n;j++) { if(data[i]<data[j]&&dp[j]==dp[i]+1) adde(2*i^1,2*j,inf); } } } } int sap_gap(int u,int f,int s,int t) { if(u==t) return f; int i,v,mind=t,last=f,cost; for(i=head[u];i!=-1;i=e[i].next) { v=e[i].v; int flow=e[i].f; if(flow>0) { if(d[u]==d[v]+1) { cost=sap_gap(v,min(last,flow),s,t); e[i].f-=cost; e[i^1].f+=cost; last-=cost; if(d[s]>=t+1) return f-last; if(last==0) break; } if(d[v]<mind) mind=d[v]; } } if(last==f) { --num[d[u]]; if(num[d[u]]==0) d[s]=t+1; d[u]=mind+1; ++num[d[u]]; } return f-last; } int pro2() { build(); int f=0; memset(d,0,sizeof(d)); memset(num,0,sizeof(num)); for(num[s]=t+1;d[s]<t+1;) f+=sap_gap(s,inf,s,t); return f; } int main() { int i; while(scanf("%d",&n)!=EOF) { for(i=0;i<n;i++) scanf("%d",&data[i]); m=pro(); printf("%d\n",m); m=pro2(); printf("%d\n",m); } return 0; }