博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【网络流24题】最长不下降子序列问题
阅读量:5905 次
发布时间:2019-06-19

本文共 3262 字,大约阅读时间需要 10 分钟。

题目描述

«问题描述:

给定正整数序列x1,...,xn 。

(1)计算其最长不下降子序列的长度s。

(2)计算从给定的序列中最多可取出多少个长度为s的不下降子序列。

(3)如果允许在取出的序列中多次使用x1和xn,则从给定序列中最多可取出多少个长度为s的不下降子序列。

«编程任务:

设计有效算法完成(1)(2)(3)提出的计算任务。

输入输出格式

输入格式:

 

第1 行有1个正整数n,表示给定序列的长度。接下来的1 行有n个正整数n:x1, ..., xn。

 

输出格式:

 

第1 行是最长不下降子序列的长度s。第2行是可取出的长度为s 的不下降子序列个数。第3行是允许在取出的序列中多次使用x1和xn时可取出的长度为s 的不下降子序列个数。

 

输入输出样例

输入样例#1: 
43 6 2 5
输出样例#1: 
223

说明

n\le 500n500


这里我们先说明下题意:

第二问里用过的元素不能再用,即取出的最多的不重叠的最长不下降子序列数量

而第3问里,x1,xn可以重复用,但是出现过一次的序列不能再出现

搞明白他要什么了之后就可以考虑构图了

针对每个数智能用一次的限制,我们可以让i裂成$i$和$i'$

从$i$到$i'$连一条1的边,就可以保证只用一次

接下来我们考虑如何在各个点之间连边

在第一问时我们处理出$f[i]$,从i出发所能接出的最长序列

不难发现,无论拿出的时哪几个序列,如果要充分利用的话,$i$必然向$f[j]==f[i]-1$的$j$连边

所以我们对于每个$i'$,找到所有能接在它后面且$f[j]==f[i]-1$的$j$,连$i'->j$为1

最后对于所有$f[i]==s$的连$S-inf->i$,$f[i]==1$的连$i'-inf->T$

至于为什么是inf嘛。。是为了方便1和n,当然这里可以分别处理吧(懒得想了

1 #include
2 #define N 2005 3 #define M 300000 4 #define INF (1<<30) 5 using namespace std; 6 int h[N],to[M],nxt[M],fl[M],etop; 7 int S=0,T=2000,n,x[505],f[505]; 8 void add(int u,int v,int w){ 9 //printf("%d %d %d\n",u,v,w);10 to[etop]=v,nxt[etop]=h[u],fl[etop]=w,h[u]=etop++;11 to[etop]=u,nxt[etop]=h[v],fl[etop]=0,h[v]=etop++;12 }13 queue
q;14 int lev[N];15 inline bool bfs(){16 memset(lev,-1,sizeof(lev));17 lev[S]=0;q.push(S);18 while(!q.empty()){19 int u=q.front();q.pop();20 for(int k=h[u];~k;k=nxt[k]){21 int v=to[k];22 if(lev[v]==-1&&fl[k]){23 lev[v]=lev[u]+1;24 q.push(v);25 }26 }27 }28 return lev[T]!=-1;29 }30 int dfs(int u,int t,int left){31 if(u==t)return left;32 for(int k=h[u];~k;k=nxt[k]){33 int v=to[k];34 if(lev[v]==lev[u]+1&&fl[k]){35 int d=dfs(v,t,min(left,fl[k]));36 if(d){37 fl[k]-=d;38 fl[k^1]+=d;39 return d;40 }41 }42 }43 return 0;44 }45 int dinic(){46 int flow=0,f;47 while(bfs()){48 while(f=dfs(S,T,INF))flow+=f;49 }50 return flow;51 }52 int s;53 void pre(){54 for(int i=n;i>=1;i--){55 for(int j=i+1;j<=n;j++)56 if(x[i]<=x[j])f[i]=max(f[i],f[j]);57 f[i]++;58 s=max(s,f[i]);59 }60 }61 int main(){62 scanf("%d",&n);63 for(int i=1;i<=n;i++)scanf("%d",&x[i]);64 pre();65 printf("%d\n",s);66 if(s==1){67 printf("%d\n%d",n,n);68 return 0;69 }70 memset(h,-1,sizeof(h));71 for(int i=1;i<=n;i++){72 add(i<<1,i<<1|1,1);73 for(int j=i+1;j<=n;j++)74 if(f[i]==f[j]+1&&x[i]<=x[j])75 add(i<<1|1,j<<1,1);76 if(f[i]==1)add(i<<1|1,T,INF);77 if(f[i]==s)add(S,i<<1,INF);78 }79 printf("%d\n",dinic());80 memset(h,-1,sizeof(h));81 etop=0;82 for(int i=1;i<=n;i++){83 if(i==1||i==n)add(i<<1,i<<1|1,INF);84 else add(i<<1,i<<1|1,1);85 for(int j=i+1;j<=n;j++)86 if(f[i]==f[j]+1&&x[i]<=x[j])87 add(i<<1|1,j<<1,1);88 if(f[i]==1)add(i<<1|1,T,INF);89 if(f[i]==s)add(S,i<<1,INF);90 }91 printf("%d\n",dinic());92 return 0;93 }94 /*95 696 4 7 1 6 4 397 */
View Code

当然如果你也这样连边,别忘了特判坑爹的s==1,不然会出正无穷的。。。

 

转载于:https://www.cnblogs.com/2017SSY/p/10847951.html

你可能感兴趣的文章
ASP.NET中 DataList(数据列表)的使用前台绑定
查看>>
Linux学习之CentOS(八)--Linux系统的分区概念
查看>>
System.Func<>与System.Action<>
查看>>
asp.net开源CMS推荐
查看>>
csharp skype send message in winform
查看>>
MMORPG 游戏服务器端设计--转载
查看>>
HDFS dfsclient写文件过程 源码分析
查看>>
ubuntu下安装libxml2
查看>>
nginx_lua_waf安装测试
查看>>
WinForm窗体缩放动画
查看>>
JQuery入门(2)
查看>>
linux文件描述符
查看>>
传值引用和调用引用的区别
查看>>
hyper-v 无线网连接
查看>>
Python3.7.1学习(六)RabbitMQ在Windows环境下的安装
查看>>
Windows下memcached的安装配置
查看>>
ubuntu: firefox+flashplay
查看>>
web.xml 中CharacterEncodingFilter类的学习
查看>>
贪吃蛇逻辑代码
查看>>
实现c协程
查看>>