码迷,mamicode.com
首页 > 其他好文 > 详细

[网络流24题] 最长递增子序列

时间:2017-12-28 18:23:35      阅读:265      评论:0      收藏:0      [点我收藏+]

标签:允许   top   限制   head   简单   取出   out   正整数   bit   

[网络流24题] 最长递增子序列

 

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

注意:这里的最长递增子序列即最长不下降子序列!!!
«编程任务:
设计有效算法完成(1)(2)(3)提出的计算任务。
«数据输入:
由文件alis.in提供输入数据。文件第1 行有1个正整数n(n<=500),表示给定序列的长度。接
下来的1 行有n个正整数x1,..., xn。
«结果输出:
程序运行结束时,将任务(1)(2)(3)的解答输出到文件alis.out中。第1 行是最长
递增子序列的长度s。第2行是可取出的长度为s 的递增子序列个数。第3行是允许在取出
的序列中多次使用x1和xn时可取出的长度为s 的递增子序列个数。
输入文件示例 输出文件示例
alis.in
4

3 6 2 5

alis.out

2
2
3

 

 

题目描述的不是很清楚,不是递增,是不下降,另外无限用事实上指的是1和n可以被用于多个不下降序列中,可以重复使用,而其他点只可以用一次。

对于第一问,随便求一下就行...

对于后两问,我们想到网络流的方法(毕竟网络流24题),如何限制一个点的经过次数呢?我们可以把它拆成两个点,在两个点之间连一条权值为x的边,表示这个点最多经过x次。那如何建图呢,对于两个位置i,j,如果a[i]<=a[j]并且i<j并且g[i]+1=g[j],那么我们就可以在他们之间连一条边,想一下也很简单。那么与源点(S)和汇点(T)如何连边呢?

对于第二问的情况,连1就行了,因为最多用一次。

对于第三问,非无限取的点和第二问一样,对于无限取的点,他与S相连的权值至少应该为他可能作为起点出现的次数a,与T相连的权值至少应该为他可能作为终点出现的次数b。对于只与S或者只与T相连的点,这种点的存在说明了最长不下降子序列长度不为1,我们边的权值可以取任意大于等于a或者b数字,因为其他的点会对他做出限制,他取大一点也没关系,反正也流不了那么多,但对于s与t均连在一个点上的情况,说明最长不下降序列长度为1,这时候a,b中比较小的那一个(其实这种情况全是1),就必须取他本身,也就是1,才能“限制”住,不然的话他的流量就变成inf了。而1这个点又比较特殊,如果他可以作为终点出现,那么说明最长不下降序列长度为1,也就一定可以作为起点出现,那么1和t的连边权值一定是1,n点同理,与s连边权值一定是1,。

语文比较差,,,可能讲不清楚。也可能讲的就是错的qwq,因为我yy了一下午也就很牵强的说服了自己。。。

技术分享图片
  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 const int inf=1e6;//随便开...
  4 int n,a[inf],f[inf],g[inf],top;
  5 int tot,fi[inf],to[inf],next[inf],cost[inf],rev[inf];
  6 int ans,que[inf],head,tail,dep[inf],cur[inf]; 
  7 void slove1(){
  8     for(int i=1;i<=n;i++){
  9         if(a[i]>=f[top])f[++top]=a[i],g[i]=top;
 10         else {
 11             int l=1,r=top;
 12             while(l!=r){
 13                 int mid=(l+r)>>1;
 14                 if(f[mid]<=a[i])l=mid+1;
 15                 else r=mid;
 16             }
 17             f[l]=a[i];
 18             g[i]=l;
 19         }
 20     }
 21     printf("%d\n",top);
 22 }
 23 void edge_add(int x,int y,int z){
 24     to[++tot]=y;next[tot]=fi[x];
 25     fi[x]=tot;cost[tot]=z;rev[tot]=tot+1;
 26     to[++tot]=x;next[tot]=fi[y];
 27     fi[y]=tot;cost[tot]=0;rev[tot]=tot-1;
 28 }
 29 bool bfs(){
 30     for(int i=1;i<=n*2+2;i++)cur[i]=fi[i],dep[i]=-1;
 31     dep[1]=0;
 32     head=1;tail=0;
 33     que[++tail]=1;
 34     while(head<=tail){
 35         int u=que[head++];
 36         for(int i=fi[u];i;i=next[i])
 37             if(cost[i]&&dep[to[i]]==-1)
 38                 dep[to[i]]=dep[u]+1,
 39                 que[++tail]=to[i];
 40     }
 41     return dep[n*2+2]!=-1;
 42 }
 43 int dfs(int x,int f){
 44     if(x==n*2+2)return f;
 45     for(int i=cur[x];i;i=next[i]){
 46         cur[x]=i;
 47         if(cost[i]&&dep[to[i]]==dep[x]+1){
 48             int g=dfs(to[i],min(f,cost[i]));
 49             if(g){
 50                 cost[i]-=g;
 51                 cost[rev[i]]+=g;
 52                 return g;
 53             }
 54         }
 55     }
 56     return 0;
 57 }
 58 void dinic(){
 59     ans=0;
 60     int f;
 61     while(bfs())
 62         while(f=dfs(1,0x3fffffff))ans+=f;
 63     printf("%d\n",ans);
 64 }
 65 int main()
 66 {
 67     freopen("alis.in","r",stdin);
 68     freopen("alis.out","w",stdout);
 69 //    freopen("1.txt","r",stdin);
 70     scanf("%d",&n);
 71     for(int i=1;i<=n;i++)scanf("%d",&a[i]);
 72     slove1();
 73     for(int i=1;i<=n;i++){
 74         edge_add(i<<1,i<<1|1,1);
 75         if(g[i]==1)edge_add(1,i<<1,1);
 76         if(g[i]==top)edge_add(i<<1|1,n*2+2,1);
 77     }
 78     for(int i=1;i<n;i++)
 79         for(int j=i+1;j<=n;j++)
 80             if(a[i]<=a[j]&&g[i]+1==g[j])
 81                 edge_add(i<<1|1,j<<1,1);
 82     dinic();
 83     tot=0;
 84     memset(fi,0,sizeof(fi));
 85     memset(to,0,sizeof(to));
 86     memset(next,0,sizeof(next));
 87     memset(rev,0,sizeof(rev));
 88     memset(cost,0,sizeof(cost));
 89     for(int i=1;i<=n;i++){
 90         edge_add(i<<1,i<<1|1,1);
 91         if(g[i]==1)edge_add(1,i<<1,1);
 92         if(g[i]==top)edge_add(i<<1|1,n*2+2,1);
 93     }
 94     for(int i=1;i<n;i++)
 95         for(int j=i+1;j<=n;j++)
 96             if(a[i]<=a[j]&&g[i]+1==g[j])
 97                 edge_add(i<<1|1,j<<1,1);
 98     edge_add(2,3,0x3fffffff);edge_add(n<<1,n<<1|1,0x3fffffff);
 99     if(g[1]==1)edge_add(1,2,0x3fffffff);
100     if(g[n]==top)edge_add(n<<1,n*2+2,0x3fffffff);
101     dinic();
102     return 0;
103 }
View Code

 

[网络流24题] 最长递增子序列

标签:允许   top   限制   head   简单   取出   out   正整数   bit   

原文地址:https://www.cnblogs.com/Turkeyghb/p/8136838.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!