题目描述
«问题描述:
给定正整数序列x1,…,xn 。
(1)计算其最长不下降子序列的长度s。
(2)计算从给定的序列中最多可取出多少个长度为s的不下降子序列。
(3)如果允许在取出的序列中多次使用x1和xn,则从给定序列中最多可取出多少个长度为s的不下降子序列。
«编程任务:
设计有效算法完成(1)(2)(3)提出的计算任务。
输入输出格式
输入格式:
第1 行有1个正整数n,表示给定序列的长度。接下来的1 行有n个正整数n:x1, …, xn。
输出格式:
第1 行是最长不下降子序列的长度s。第2行是可取出的长度为s 的不下降子序列个数。第3行是允许在取出的序列中多次使用x1和xn时可取出的长度为s 的不下降子序列个数。
输入输出样例
说明
n≤500
第一问用dp求出LIS长len和f[i]
把一个点拆成x, y
从s到f[i]=len的点x,流量为1
从f[i]=1的点y到t,流量为1
从点x到点y,流量为1
从a[j]≤a[i]且f[j]+1=f[i]的点iy到点jx,流量为1
第三问只需要接触1和n的流量限制就行了
注意:不下降时小于等于
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
#include<stdio.h> #include<string.h> #include<queue> #define MAXN 510 #define INF 1e9 #define min(a, b) ((a) < (b) ? (a) : (b)) #define max(a, b) ((a) > (b) ? (a) : (b)) using namespace std; struct Edge { int u, v, w, next; } e[MAXN*MAXN*4]; int n, f[MAXN], dep[2*MAXN], h[2*MAXN], cnt = 1, s, t, a[MAXN], ans1, ans2; void addEdge(int ui, int vi, int wi) { e[++cnt] = (Edge) {ui, vi, wi, h[ui]}; h[ui] = cnt; e[++cnt] = (Edge) {vi, ui, 0, h[vi]}; h[vi] = cnt; } int bfs() { memset(dep, 0, sizeof(dep)); dep[s] = 1; queue<int> q; q.push(s); while (!q.empty()) { int u = q.front(); for (int i = h[u]; i; i = e[i].next) { if (e[i].w > 0 && !dep[e[i].v]) { dep[e[i].v] = dep[u]+1; q.push(e[i].v); } } q.pop(); } return dep[t]; } int dfs(int u, int w) { int flow = 0; if (u == t) return w; for (int i = h[u], wi, k; i; i = e[i].next) { wi = min(w, e[i].w); if (wi > 0 && dep[e[i].v] == dep[u]+1) { flow += k = dfs(e[i].v, wi); w -= k; e[i].w -= k; e[i^1].w += k; } } return flow ? flow : dep[u] = 0; } int Dinic() { int flow = 0; while (bfs()) flow += dfs(s, INF); return flow; } int main() { scanf("%d", &n); s = 0; t = 2*n+1; for (int i = 1; i <= n; ++i) { scanf("%d", &a[i]); f[i] = 1; for (int j = 1; j < i; ++j) { if (a[j] <= a[i] && f[j]+1 > f[i]) f[i] = f[j]+1; } ans1 = max(ans1, f[i]); } printf("%d\n", ans1); for (int i = 1; i <= n; ++i) { addEdge(i, i+n, 1); if (f[i] == ans1) addEdge(s, i, 1); if (f[i] == 1) addEdge(i+n, t, 1); for (int j = 1; j < i; ++j) { if (a[j] <= a[i] && f[j]+1 == f[i]) addEdge(i+n, j, 1); } } printf("%d\n", ans2 = Dinic()); addEdge(1, 1+n, INF); addEdge(1+n, t, INF); if (f[n] == ans1) { addEdge(n, n+n, INF); addEdge(s, n, INF); } printf("%d\n", ans2+Dinic()); return 0; } |