网络流24题之最长不下降子序列

对于第一问直接n^2dp计算

第二问建图跑网络流

第三问将起始与结尾流量开大

建边的时候要严格按照子序列求法建

By:大奕哥

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int N=10005;
 4 int head[N],d[N],f[N],a[N];
 5 int n,m,cnt=-1,s,t,sum;
 6 struct node{
 7     int to,nex,w;
 8 }e[1000005];
 9 void add(int x,int y,int w)
10 {
11     e[++cnt].to=y;e[cnt].nex=head[x];head[x]=cnt;e[cnt].w=w;
12     e[++cnt].to=x;e[cnt].nex=head[y];head[y]=cnt;e[cnt].w=0;
13 }
14 queue<int>q;
15 bool bfs(int x,int y)
16 {
17     memset(d,-1,sizeof(d));
18     d[x]=0;q.push(x);
19     while(!q.empty())
20     {
21         int x=q.front();q.pop();
22         for(int i=head[x];i!=-1;i=e[i].nex)
23         {
24             int y=e[i].to;
25             if(d[y]!=-1||!e[i].w)continue;
26             d[y]=d[x]+1;q.push(y);
27         }
28     }
29     return d[y]!=-1;
30 }
31 int dfs(int x,int w,int yy)
32 {
33     if(x==yy||!w)return w;
34     int s=0;
35     for(int i=head[x];i!=-1;i=e[i].nex)
36     {
37         int y=e[i].to;
38         if(!e[i].w||d[y]!=d[x]+1)continue;
39         int flow=dfs(y,min(w-s,e[i].w),yy);
40         if(!flow){
41             d[y]=-1;continue;
42         }
43         e[i].w-=flow;e[i^1].w+=flow;s+=flow;
44         if(s==w)return s;
45     }
46     return s;
47 }
48 int dinic()
49 {
50     int ans=0;
51     while(bfs(s,t))
52     {
53         ans+=dfs(s,1e9,t);
54     }
55     return ans;
56 }
57 int main()
58 {
59
60     freopen("1.out","r",stdin);
61     freopen("my.out","w",stdout);
62     scanf("%d",&n);
63     memset(head,-1,sizeof(head));
64     for(int i=1;i<=n;++i)
65     {
66         scanf("%d",&a[i]);
67         add(i,i+n,1);
68     }
69     s=0,t=n+n+10;int ans=1;
70     for(int i=1;i<=n;++i)
71     {
72         f[i]=max(f[i],1);add(i,i+n,1);
73         for(int j=i+1;j<=n;++j)
74         if(a[j]>=a[i])
75         {
76             f[j]=max(f[j],f[i]+1);
77             ans=max(f[j],ans);
78         }
79     }int pre=ans;
80     for(int i=1;i<=n;++i)
81     for(int j=i+1;j<=n;++j)
82     if(f[j]==f[i]+1&&a[j]>=a[i])
83     add(i+n,j,1);
84     printf("%d\n",ans);
85     for(int i=1;i<=n;++i)
86     {if(f[i]==1)add(s,i,1);
87     if(f[i]==ans)add(i+n,t,1);}
88     ans=dinic();
89     printf("%d\n",ans);
90     add(s,1,1e9);add(1,n+1,1e9);
91     if(f[n]==pre)
92     add(n+n,t,1e9),add(n,n+n,1e9);
93     ans+=dinic();
94     printf("%d\n",ans);
95     return 0;
96 }

原文地址:https://www.cnblogs.com/nbwzyzngyl/p/8394285.html

时间: 2024-07-30 22:13:46

网络流24题之最长不下降子序列的相关文章

【网络流24题】最长不下降子序列(最大流,动态规划)

[网络流24题]最长不下降子序列(最大流,动态规划) 题面 Cogs 题解 很有趣的一道题目 尽管我自己还是有一些懵逼 第一问,直接大力DP一下,不解释了 第二问,考虑到一个长度为ans的子序列的开头 他的dp值一定等于ans, 所以,如果一个点的dp值为ans,就从源点连过去,容量为1 因为每个数只能用一次,因此拆点 自己向自己的新点连容量为1的边 一个子序列的结束的位置其dp值必定为1 所以从dp值为1的新点向汇点连边,容量为1 接下来考虑点与点之间的关系 如果dp[i]=dp[j]+1 并

「网络流24题」最长不下降子序列问题

传送门:>Here< 题意: 给定正整数序列$x_1,...,x_n$ (1)计算其最长不下降子序列的长度s. (2)计算从给定的序列中最多可取出多少个长度为s的不下降子序列. (3)如果允许在取出的序列中多次使用$x_1$和$x_n$,则从给定序列中最多可取出多少个长度为$s$的不下降子序列. 思路分析 题意首先就很坑:注意第二问中的取出二字,意味着一个数字最多只能存在于一个LIS中.所以才会有第三问的假设 第一问很简单,直接暴力$O(n^2)$就好了 后面的两问需要借助于网络流.很容易想到

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

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

【网络流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 行是最长递增子序列的

[cogs731] [网络流24题#6] 最长递增子序列 [网络流,最大流]

[转hzwer]第一问是LIS,动态规划求解,第二问和第三问用网络最大流解决.首先动态规划求出F[i],表示以第i位为开头的最长上升序列的长度,求出最长上升序列长度K.1.把序列每位i拆成两个点<i.a>和<i.b>,从<i.a>到<i.b>连接一条容量为1的有向边.2.建立附加源S和汇T,如果序列第i位有F[i]=K,从S到<i.a>连接一条容量为1的有向边.3.如果F[i]=1,从<i.b>到T连接一条容量为1的有向边.4.如果j

网络流24题之最长k可重线段集问题

对于每个线段拆成两个点,如同之前一样建图,由于可能出现垂直于x轴的 所以建图由i指向i~ 继续最小费用最大流 By:大奕哥 1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=10000005,inf=1e9; 4 int head[N],d[N],f[N],l1[N],r1[N],l2[N],r2[N],a[N],s=1e9,t,n,k,cnt=-1; 5 long long cost; 6 bool v[N]; 7

*LOJ#6227. 「网络流 24 题」最长k可重线段集问题

$n \leq 500$条平面上的线段,问一种挑选方法,使得不存在直线$x=p$与挑选的直线有超过$k$个交点,且选得的直线总长度最长. 横坐标每个点开一个点,一条线段就把对应横坐标连一条容量一费用(-长度)的边:点$x$向点$x+1$连一条容量$k$费用0的边.这里的$k$边限制的是直线上其他不经过这里的地方. 这里有个trick就是有与$x$轴垂直的线段.直接判掉会wa.为此把坐标扩大两倍,如果$l=r$那么$r++$否则$l++$,相当于把一个点拆成两个. 原文地址:https://www

「网络流 24 题」最长 k 可重区间集

给定区间集合$I$和正整数$k$, 计算$I$的最长$k$可重区间集的长度. 区间离散化到$[1,2n]$, $S$与$1$连边$(k,0)$, $i$与$i+1$连边$(k,0)$, $2n$与$T$连边$(k,0)$. 对于每个区间$(l,r)$, $l$与$r$连边$(1,l-r)$. 最小费用相反数就为最大长度 #include <iostream> #include <sstream> #include <algorithm> #include <cst