COGS731 [网络流24题] 最长递增子序列(最大流)

给定正整数序列x1,..., xn (n<=500)。
(1)计算其最长递增子序列的长度s。
(2)计算从给定的序列中最多可取出多少个长度为s的递增子序列。
(3)如果允许在取出的序列中多次使用x1和xn,则从给定序列中最多可取出多少个长
度为s的递增子序列。

这题求的其实是最长非递减子序列。。

第一问,是个经典的DP,dp[i]表示序列x1...xi且以xi结尾的LIS。

第二问,这么建容量网络:

    • x1...xn中每个i,拆作两点i和i',连<i,i'>容量1的边
    • 源点和所有dp[i]==1的i,连<vs,i>容量1的边
    • 汇点和所有dp[i]==s的i,连<i',vt>容量1的边
    • 对于所有xi<=xj且dp[i]==dp[j]+1的i和j,连<i',j>的容量1的边

  然后其最大流就是答案。

第三问,在第二问基础上把与x1和xn相关的边容量设置成INF跑最大流。另外如果LIS为1,那样直接输出n,不然结果会是INF。

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<queue>
  4 #include<algorithm>
  5 using namespace std;
  6 #define INF (1<<30)
  7 #define MAXN 1111
  8 #define MAXM 2222222
  9 
 10 struct Edge{
 11     int v,cap,flow,next;
 12 }edge[MAXM];
 13 int vs,vt,NE,NV;
 14 int head[MAXN];
 15 
 16 void addEdge(int u,int v,int cap){
 17     edge[NE].v=v; edge[NE].cap=cap; edge[NE].flow=0;
 18     edge[NE].next=head[u]; head[u]=NE++;
 19     edge[NE].v=u; edge[NE].cap=0; edge[NE].flow=0;
 20     edge[NE].next=head[v]; head[v]=NE++;
 21 }
 22 
 23 int level[MAXN];
 24 int gap[MAXN];
 25 void bfs(){
 26     memset(level,-1,sizeof(level));
 27     memset(gap,0,sizeof(gap));
 28     level[vt]=0;
 29     gap[level[vt]]++;
 30     queue<int> que;
 31     que.push(vt);
 32     while(!que.empty()){
 33         int u=que.front(); que.pop();
 34         for(int i=head[u]; i!=-1; i=edge[i].next){
 35             int v=edge[i].v;
 36             if(level[v]!=-1) continue;
 37             level[v]=level[u]+1;
 38             gap[level[v]]++;
 39             que.push(v);
 40         }
 41     }
 42 }
 43 
 44 int pre[MAXN];
 45 int cur[MAXN];
 46 int ISAP(){
 47     bfs();
 48     memset(pre,-1,sizeof(pre));
 49     memcpy(cur,head,sizeof(head));
 50     int u=pre[vs]=vs,flow=0,aug=INF;
 51     gap[0]=NV;
 52     while(level[vs]<NV){
 53         bool flag=false;
 54         for(int &i=cur[u]; i!=-1; i=edge[i].next){
 55             int v=edge[i].v;
 56             if(edge[i].cap!=edge[i].flow && level[u]==level[v]+1){
 57                 flag=true;
 58                 pre[v]=u;
 59                 u=v;
 60                 //aug=(aug==-1?edge[i].cap:min(aug,edge[i].cap));
 61                 aug=min(aug,edge[i].cap-edge[i].flow);
 62                 if(v==vt){
 63                     flow+=aug;
 64                     for(u=pre[v]; v!=vs; v=u,u=pre[u]){
 65                         edge[cur[u]].flow+=aug;
 66                         edge[cur[u]^1].flow-=aug;
 67                     }
 68                     //aug=-1;
 69                     aug=INF;
 70                 }
 71                 break;
 72             }
 73         }
 74         if(flag) continue;
 75         int minlevel=NV;
 76         for(int i=head[u]; i!=-1; i=edge[i].next){
 77             int v=edge[i].v;
 78             if(edge[i].cap!=edge[i].flow && level[v]<minlevel){
 79                 minlevel=level[v];
 80                 cur[u]=i;
 81             }
 82         }
 83         if(--gap[level[u]]==0) break;
 84         level[u]=minlevel+1;
 85         gap[level[u]]++;
 86         u=pre[u];
 87     }
 88     return flow;
 89 }
 90 
 91 int d[555],a[555]; 
 92 int main(){
 93     freopen("alis.in","r",stdin);
 94     freopen("alis.out","w",stdout);
 95     int n;
 96     scanf("%d",&n);
 97     for(int i=1; i<=n; ++i) scanf("%d",a+i);
 98     int lis=0;
 99     for(int i=1; i<=n; ++i){
100         d[i]=1;
101         for(int j=1; j<i; ++j){
102             if(a[j]<=a[i]) d[i]=max(d[i],d[j]+1);
103         }
104         lis=max(lis,d[i]);
105     }
106     printf("%d\n",lis);
107     if(lis==1){
108         printf("%d\n%d",n,n);
109         return 0;
110     }
111     vs=0; vt=n<<1|1; NV=vt+1; NE=0;
112     memset(head,-1,sizeof(head));
113     for(int i=1; i<=n; ++i){
114         if(d[i]==1) addEdge(vs,i,1);
115         if(d[i]==lis) addEdge(i+n,vt,1);
116         addEdge(i,i+n,1);
117     }
118     for(int i=1; i<n; ++i){
119         for(int j=i+1; j<=n; ++j){
120             if(a[j]>=a[i] && d[j]==d[i]+1) addEdge(i+n,j,1);
121         }
122     }
123     printf("%d\n",ISAP());
124     vs=0; vt=n<<1|1; NV=vt+1; NE=0;
125     memset(head,-1,sizeof(head));
126     for(int i=1; i<=n; ++i){
127         if(i==1 || i==n){
128             if(d[i]==1) addEdge(vs,i,INF);
129             if(d[i]==lis) addEdge(i+n,vt,INF);
130             addEdge(i,i+n,INF);
131         }else{
132             if(d[i]==1) addEdge(vs,i,1);
133             if(d[i]==lis) addEdge(i+n,vt,1);
134             addEdge(i,i+n,1);
135         }
136     }
137     for(int i=1; i<n; ++i){
138         for(int j=i+1; j<=n; ++j){
139             if(a[j]>=a[i] && d[j]==d[i]+1) addEdge(i+n,j,1);
140         }
141     }
142     printf("%d\n",ISAP());
143     return 0;
144 }

 

posted @ 2016-03-14 22:19  WABoss  阅读(254)  评论(0编辑  收藏  举报