1. 程式人生 > >網路流24題6 最長遞增子序列

網路流24題6 最長遞增子序列

題目描述

給定正整數序列x1,…,xn 。

(1)計算其最長遞增子序列的長度s。

(2)計算從給定的序列中最多可取出多少個長度為s的遞增子序列。

(3)如果允許在取出的序列中多次使用x1和xn,則從給定序列中最多可取出多少個長度為s的遞增子序列。

設計有效演算法完成(1)(2)(3)提出的計算任務。

Analysis

第一問秒掉
第二問比較難想到,每個i節點按f[i]不同分了很多層,那麼每次s到t的一條合法路徑都是滿足條件的序列。由於序列中每個點不可重複,需要拆點。邊權是1所以最大流就是增廣路的條數,所以最大流量就是第二問結果
第三問特殊地要求x1和xn可以重複使用,那麼就取消這兩個點相關邊的流量限制,求網路最大流即可。

略坑爹,題目求的不是上升序列而是不下降序列
如果要求點不能重複使用,那麼拆點是一種可行的方法

洛谷死活不能過,蛋疼

Code

/*
ID:wjp13241
PROG:
LANG:C++
*/
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <ctime>
#include <algorithm>
#include <iostream>
#include <vector>
#include <cmath>
#include <stack> #include <queue> #include <map> #define fo(i,a,b) for(int i=a;i<=b;i++) #define dfo(i,a,b) for(int i=a;i>=b;i--) #define fore(i,x,e) for(int i=ls[x];i;i=e[i].next) #define fil(x,t) memset(x,t,sizeof(x)) #define FILEIN(s) freopen(s,"r",stdin) #define FILEOUT(s) freopen(s,"w",stdout)
#define STP system("pause") #define min(x,y) x<y?x:y #define max(x,y) x>y?x:y #define MP(x,y) make_pair(x,y) #define PuB(v,x) v.push_back(x) #define PoB(v) v.pop_back() #define ld long double #define ll long long #define db double #define INF 0x3f3f3f3f #define LIM 100000000 #define EPS 1e-4 #define N 10201 #define E N*20+1 #define ST 0 #define ED N-1 #define L 21 using namespace std; struct edge{int y, w, next;}e[E]; int num[N], dis[N], cur[N], ls[N], f[N], maxE = 0; int add(int x, int y, int w){ e[++maxE] = (edge){y, w, ls[x]};ls[x] = maxE; e[++maxE] = (edge){x, 0, ls[y]};ls[y] = maxE; } int bfs(int st, int ed){ queue<int>q; q.push(st); fil(dis, 63); dis[st] = 0; while (!q.empty()){ int now = q.front();q.pop(); for (int i = ls[now]; i; i = e[i].next){ if (e[i].w > 0 && dis[now] + 1 < dis[e[i].y]){ q.push(e[i].y); dis[e[i].y] = dis[now] + 1; if (e[i].y == ed){ return 1; } } } } return 0; } int find(int now, int ed, int mn){ if (now == ed){ return mn; } for (int &i = cur[now]; i; i = e[i].next){ if (e[i].w > 0 && dis[now] + 1 == dis[e[i].y]){ int d = find(e[i].y, ed, min(mn, e[i].w)); if (d > 0){ e[i].w -= d; e[i ^ 1].w += d; return d; } } } return 0; } int build(int n){ fo(i, 1, n){ fo(j, i + 1, n){ if (f[j] == f[i] + 1 && num[i] <= num[j]){ add(i + n, j, 1); } } } } int dinic(int n){ int mxFlow = 0; while (bfs(ST, ED)){ fo(i, 1, n + n){ cur[i] = ls[i]; } cur[ST] = ls[ST]; cur[ED] = ls[ED]; mxFlow += find(ST, ED, INF); } return mxFlow; } int main(){ ios::sync_with_stdio(false); int n; cin>> n; fo(i, 1, n) cin>> num[i]; int ans = 0; fo(i, 1, n){ f[i] = 1; fo(j, 1, i-1){ if (num[j] <= num[i]){ f[i] = max(f[i], f[j] + 1); } ans = max(ans, f[i]); } } cout<< ans<< endl; fo(i, 1, n){ if (f[i] == 1){ add(ST, i, 1); } if (f[i] == ans){ add(i + n, ED, 1); } add(i, i+n, 1); } build(n); int mxFlow = dinic(n); cout<< mxFlow <<endl; fil(ls, 0); maxE = 0; fo(i, 1, n){ int v = (i == 1 || i == n)? INF: 1; if (f[i] == 1){ add(ST, i, v); } if (f[i] == ans){ add(i + n, ED, v); } add(i, i+n, v); } build(n); mxFlow = dinic(n); cout<< mxFlow <<endl; return 0; }