【网络流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

pre.cjk { font-family: "Droid Sans Fallback", monospace }
p { margin-bottom: 0.25cm; line-height: 120% }
a:link { }

一开始自己想了个很鬼的模型30分,后来分析完全是错的。
我那个模型并没有求最大流,只是在残余网络上找路径,所以不能保证答案是最大的。
先DP求出以每个点的为起点的最长不下降序列长度,以为f[i];
注意是最长不下降,这题题面与数据不符合(坑了我1个小时)
将一个点一分为二,分为A部和B部。
Ai和Bi连一条容量为1的边。
若f[i]==MAX
S->Ai,若f[i]==1
Bi->T。
枚举i后面的j,若a[i]<=a[j]
且f[j]+1==f[i],
连Bi->Aj。
然后跑最大流。
第三问是一样的,只是把S和T连1和n还有A1连B1的边,An连Bn的边容量改为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 }

 
时间: 2024-10-12 23:56:55

【网络流24题】最长递增子序列的相关文章

[网络流24题] 最长递增子序列 (最多不相交路径---网络最大流)

731. [网络流24题] 最长递增子序列 ★★★☆ 输入文件:alis.in 输出文件:alis.out 简单对比 时间限制:1 s 内存限制:128 MB «问题描述: 给定正整数序列x1,..., xn. (1)计算其最长递增子序列的长度s. (2)计算从给定的序列中最多可取出多少个长度为s的递增子序列. (3)如果允许在取出的序列中多次使用x1和xn,则从给定序列中最多可取出多少个长 度为s的递增子序列. «编程任务: 设计有效算法完成(1)(2)(3)提出的计算任务. «数据输入: 由

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

[网络流24题] 最长递增子序列 «问题描述:给定正整数序列x1,..., xn.(1)计算其最长递增子序列的长度s.(2)计算从给定的序列中最多可取出多少个长度为s的递增子序列.(3)如果允许在取出的序列中多次使用x1和xn,则从给定序列中最多可取出多少个长度为s的递增子序列. 注意:这里的最长递增子序列即最长不下降子序列!!!«编程任务:设计有效算法完成(1)(2)(3)提出的计算任务.«数据输入:由文件alis.in提供输入数据.文件第1 行有1个正整数n(n<=500),表示给定序列的长

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

题目大意:给定长度为n的序列a,求:1.最长递增子序列长度:2.最多选出几个不相交的最长递增子序列:3.最多选出几种在除了第1个和第n个以外的地方不相交的最长递增子序列.(n<=1000) 思路:先倒着DP,求出f[i]表示以a[i]开头的最长的递增子序列长度,然后建图,若f[i]=最长递增子序列长度则S向i连1,若f[i]=1则i向T连1,若i<j且a[i]<a[j]且f[i]=f[j]+1则i向j连1,为保证每个点只被流一次,拆成入点和出点,流量限制1,跑最大流即可解决第二问,点1和

洛谷2766:[网络流24题]最长不下降子序列问题——题解

https://www.luogu.org/problemnew/show/P2766 给定正整数序列x1,...,xn . (1)计算其最长不下降子序列的长度s. (2)计算从给定的序列中最多可取出多少个长度为s的不下降子序列. (3)如果允许在取出的序列中多次使用x1和xn,则从给定序列中最多可取出多少个长度为s的不下降子序列. 第一问用dp求解不多说了. 考虑第二问,每个数只用一次很好办,把数拆点(入点和出点)中间连边权为1的边即可. 现在的问题就是如何让它能够跑满s个点. 我们设dp[i

P2766 [网络流24题]最长不下降子序列问题

ha~ ?问题描述: 给定正整数序列$x_1,...,x_n$ .$n<=500$ 求(1)计算其最长不下降子序列的长度$s$. (2)计算从给定的序列中最多可取出多少个长度为$s$的不下降子序列. (3)如果允许在取出的序列中多次使用$x_1$和$x_n$,则从给定序列中最多可取出多少个长度为$s$的不下降子序列. (1)暴力n方解决 (2)建分层图,把图每个顶点i按照F[i]的不同分为若干层,这样图中从S出发到T的任何一条路径都是一个满足条件的最长不下降子序列.由 S 向所有$ f_i =

[网络流24题]最长不下降子序列问题

[luogu 2766] 最长不下降子序列问题 传送门 第一问: \(O(n^2)\) 的DP求LIS 为了下面叙述方便,我们将DP过程讲一遍 子状态:dp[i]表示以a[i]结尾的LIS长度 初始条件:dp[i]=1 状态转移方程:\(dp[i]=dp[j]+1(j<i,a[j]\leq a[i])\) 第二问: 我们发现若a[j]加上a[i]可以构成一个不下降子序列,则\(j<i,a[j] \leq a[i]\) 又发现每个元素只能在一个序列中,考虑拆点 建图方法: 原点S=0,T=2n+

[网络流 24 题]最长k可重区间集(费用流)

Description 给定实直线L 上n 个开区间组成的集合I,和一个正整数k,试设计一个算法,从开区间集合I 中选取出开区间集合S属于I,使得在实直线L 的任何一点x,S 中包含点x 的开区间个数不超过k,且sum(|z|)z属于S,达到最大.这样的集合S称为开区间集合I的最长k可重区间集.sum(|z|) z属于S称为最长k可重区间集的长度.对于给定的开区间集合I和正整数k,计算开区间集合I的最长k可重区间集的长度. Solution 1.离散化 然后从每个点i向i+1连一条流量为INF,

网络流24题小结

网络流24题 前言 网络流的实战应用篇太难做了,因此先完善这一部分 ## 第一题:飞行员配对方案 \(BSOJ2542\)--二分图 最优匹配 题意 两国飞行员\(x\)集合\(y\)集合,\(x\)飞行员可以配对特定的\(y\)集合的飞行员(可无),求一对一配对最大数 Solution 二分图最大匹配裸题,最大流实现 建图:(设\(i\in x\)而\(i'\in y\)) \((S,i,1)~(i',T,1)\) 对\((i,j')\)可匹配\((i,j',1)\) Code 略 ## 第二

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

(题目复制自洛谷) 题目描述 给定正整数序列x1,...,xn . (1)计算其最长递增子序列的长度s. (2)计算从给定的序列中最多可取出多少个长度为s的递增子序列. (3)如果允许在取出的序列中多次使用x1和xn,则从给定序列中最多可取出多少个长度为s的递增子序列. 编程任务: 设计有效算法完成(1)(2)(3)提出的计算任务. 输入输出格式 输入格式: 第1 行有1个正整数n,表示给定序列的长度.接下来的1 行有n个正整数n:x1, ..., xn. 输出格式: 第1 行是最长递增子序列的