标签:
【转hzwer】第一问是LIS,动态规划求解,第二问和第三问用网络最大流解决。首先动态规划求出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)这四条边的容量修改为无穷大,再求一次网络最大流,就是第三问结果。利用动规求解网络流问题。
#include <iostream> #include <algorithm> #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <ctime> #include <queue> #include <stack> #include <vector> using namespace std; #define Debug template<const int _n,const int _m> struct Edge { struct Edge_base { int to,next,w; }e[_m]; int cnt,p[_n]; Edge() { clear(); } void insert(const int x,const int y,const int z) { e[++cnt].to=y; e[cnt].next=p[x]; e[cnt].w=z; p[x]=cnt; return ; } int start(const int x) { return p[x]; } void clear() { cnt=1,memset(p,0,sizeof(p)); } Edge_base& operator[](const int x) { return e[x]; } }; Edge<11000,1100000> e; int Ans=0,tAns; int n,a[5100],cur[11000],level[11000],SSS,TTT; int f[11000]; bool Bfs(const int S) { int i,t; queue<int> Q; memset(level,0,sizeof(level)); level[S]=1; Q.push(S); while(!Q.empty()) { t=Q.front(),Q.pop(); for(i=e.start(t);i;i=e[i].next) { if(!level[e[i].to] && e[i].w) { level[e[i].to]=level[t]+1; Q.push(e[i].to); } } } return level[TTT]; } int Dfs(const int S,const int bk) { if(S==TTT)return bk; int rest=bk; for(int &i=cur[S];i;i=e[i].next) { if(level[e[i].to]==level[S]+1 && e[i].w) { int flow=Dfs(e[i].to,min(rest,e[i].w)); e[i].w-=flow; e[i^1].w+=flow; if((rest-=flow)<=0)break; } } if(rest==bk)level[S]=0; return bk-rest; } int Dinic() { int flow=0; while(Bfs(SSS)) { memcpy(cur,e.p,sizeof(cur)); flow+=Dfs(SSS,0x3f3f3f3f); } return flow; } void Calc1() { int i,j; for(i=1;i<=n;++i) { if(f[i]==1)e.insert(SSS,i,1),e.insert(i,SSS,0); if(f[i]==Ans)e.insert(i+n,TTT,1),e.insert(TTT,i+n,0); e.insert(i,i+n,1); e.insert(i+n,i,0); } for(i=1;i<=n;++i) { for(j=i+1;j<=n;++j) { if(a[j]>=a[i] && f[j]==f[i]+1) e.insert(i+n,j,1),e.insert(j,i+n,0); } } printf("%d\n",tAns=Dinic()); } void Calc2() { int i,j; e.clear(); for(i=1;i<=n;++i) { int v=1; if(i==1 || i==n)v=0x3f3f3f3f; if(f[i]==1)e.insert(SSS,i,v),e.insert(i,SSS,0); if(f[i]==Ans)e.insert(i+n,TTT,v),e.insert(TTT,i+n,0); e.insert(i,i+n,v); e.insert(i+n,i,0); } for(i=1;i<=n;++i) { for(j=i+1;j<=n;++j) { if(a[j]>=a[i] && f[j]==f[i]+1) e.insert(i+n,j,1),e.insert(j,i+n,0); } } int temp=Dinic(); if(temp>=0x3f3f3f3f)temp=tAns; printf("%d\n",temp); return ; } int main() { freopen("alis.in","r",stdin); freopen("alis.out","w",stdout); int i,j; scanf("%d",&n); for(i=1;i<=n;++i)scanf("%d",&a[i]); for(i=1;i<=n;++i) { f[i]=1; for(j=1;j<i;++j) if(a[j]<=a[i])f[i]=max(f[i],f[j]+1); Ans=max(Ans,f[i]); } printf("%d\n",Ans); SSS=n<<1|1,TTT=SSS+1; Calc1(); Calc2(); return 0; }
[cogs731] [网络流24题#6] 最长递增子序列 [网络流,最大流]
标签:
原文地址:http://www.cnblogs.com/Gster/p/4996943.html