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

[网络流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 }

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

时间: 2024-10-07 05:14: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题]最长递增子序列问题

题目大意:给定长度为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题】最长递增子序列

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行是可

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

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