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

Posted 蒟蒻ZJO :-)

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了网络流24题最长递增子序列相关的知识,希望对你有一定的参考价值。

Description

给定正整数序列x1,..., xn。
(1)计算其最长递增子序列的长度s。
(2)计算从给定的序列中最多可取出多少个长度为s的递增子序列。
(3)如果允许在取出的序列中多次使用x1和xn,则从给定序列中最多可取出多少个长度为s的递增子序列。
设计有效算法完成(1)(2)(3)提出的计算任务

Input

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

Output

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

Sample Input

4
3 6 2 5

Sample Output

2
2
3

 

 

一开始自己想了个很鬼的模型30分,后来分析完全是错的。
我那个模型并没有求最大流,只是在残余网络上找路径,所以不能保证答案是最大的。
先DP求出以每个点的为起点的最长不下降序列长度,以为f[i];
注意是最长不下降,这题题面与数据不符合(坑了我1个小时)
将一个点一分为二,分为A部和B部。
Ai和Bi连一条容量为1的边。
f[i]==MAX
->Ai,f[i]==1
Bi->T。
枚举i后面的j,若a[i]<=a[j]
f[j]+1==f[i],
Bi->Aj
然后跑最大流。
第三问是一样的,只是把S和T连1和n还有A1B1的边,AnBn的边容量改为INF。
 1 #include<set>
 2 #include<map>
 3 #include<queue>
 4 #include<stack>
 5 #include<ctime>
 6 #include<cmath>
 7 #include<string>
 8 #include<vector>
 9 #include<cstdio>
10 #include<cstdlib>
11 #include<cstring>
12 #include<iostream>
13 #include<algorithm>
14 using namespace std;
15 struct data{
16   int nex,to,w;
17 }e[530000],g[530000];
18 int head[1010],edge=-1,a[510],lev[1010],f[510],n;
19 void add(int from,int to,int w){
20   g[++edge].nex=head[from];
21   g[edge].w=w;
22   g[edge].to=to;
23   head[from]=edge;
24 }
25 bool bfs(int s,int t){
26   memset(lev,0,sizeof(lev));
27   queue<int>q;
28   q.push(s);lev[s]=1;
29   while(!q.empty()){
30     int u=q.front();
31     q.pop();
32     for(int i=head[u];i!=-1;i=e[i].nex)
33       if(!lev[e[i].to] && e[i].w>0){
34     lev[e[i].to]=lev[u]+1;
35     q.push(e[i].to);
36     if(e[i].to==t)return 1;
37       }
38   }
39   return 0;
40 }
41 int dfs(int s,int t,int k){
42   if(s==t) return k;
43   int tag=0;
44   for(int i=head[s];i!=-1;i=e[i].nex)
45     if(e[i].w>0 && lev[e[i].to]==lev[s]+1){
46       int d=dfs(e[i].to,t,min(k-tag,e[i].w));
47       e[i].w-=d;
48       e[i^1].w+=d;
49       tag+=d;
50       if(tag==k) return tag;
51     }
52   return tag;
53 }
54 void dinic(int s,int t){
55   int flow=0;
56   while(bfs(s,t)) flow+=dfs(s,t,1999999999);
57   printf("%d\n",flow);
58 }
59 int zd=0;
60 void DP(){
61   for(int i=1;i<=n;i++)
62     f[i]=1;
63   for(int i=n;i>=1;i--)
64     for(int j=i+1;j<=n;j++)
65       if(a[j]>=a[i]) f[i]=max(f[i],f[j]+1);
66   for(int i=1;i<=n;i++)
67     zd=max(zd,f[i]);
68   printf("%d\n",zd);
69 }
70 int main()
71 {
72   freopen("!.in","r",stdin);
73   freopen("!.out","w",stdout);
74   memset(head,-1,sizeof(head));
75   bool f1=0,f2=0;
76   scanf("%d",&n);
77   int s=0,t=2*n+1;
78   for(int i=1;i<=n;i++)
79     scanf("%d",&a[i]);
80   DP();
81   if(zd==1) {printf("%d\n%d\n",n,n);return 0;}
82   for(int i=1;i<=n;i++) add(i,i+n,1),add(i+n,i,0);
83   for(int i=1;i<=n;i++){
84     if(f[i]==zd){if(i==1) f1=1;add(s,i,1),add(i,s,0);}
85     if(f[i]==1) {if(i==n) f2=1;add(i+n,t,1),add(t,i+n,0);}
86   }
87   for(int i=1;i<=n;i++)
88     for(int j=i+1;j<=n;j++)
89       if(a[j]>=a[i] && f[j]+1==f[i]) add(i+n,j,1),add(j,i+n,0);
90   memcpy(e,g,sizeof(e));
91   dinic(s,t);
92   if(f1) add(s,1,1999999999),add(1,s,0);
93   if(f2) add(2*n,t,1999999999),add(t,2*n,0);
94   add(1,n+1,1999999999),add(n+1,1,0);
95   add(n,2*n,1999999999),add(2*n,n,0);
96   memcpy(e,g,sizeof(e));
97   dinic(s,t);
98   return 0;
99 }

 

 

以上是关于网络流24题最长递增子序列的主要内容,如果未能解决你的问题,请参考以下文章

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

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

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

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

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

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