网络流24题 P2766 最长不下降子序列问题
思路
问题模型:最多不相交路径
转化模型:网络最大流
比较奇妙的思路
第一个问题可以直接暴力 \(O(n^2)\) \(\texttt{DP}\) 解决,套最长不下降子序列的板子即可。
然后看第二个问题,用 \(f_i\) 表示到 \(i\) 位置的最长不下降子序列的值,将 \(i\) 拆成 \(i\) 和 \(i'\),按以下方式建图,然后跑最大流,得到的就是满足题目条件的条数:
- 如果 \(f_i=1\),说明它只能作为起点,连接 \(s\) 和 \(i\),流量为 \(1\).
- 如果 \(f_i=ans\),说明他可以作为终点,连接 \(i'\) 与 \(t\),流量为 \(1\).
- 为了保证连通性,连接 \(i\) 和 \(i’\),流量为 \(1\).
- 将满足 \(a_i\le a_i\) 且 \(f_i = f_j + 1\) 条件的 \(i’\) 和 \(j\) 连边,流量为 \(1\).
第三个问题要求取消 \(x_1\) 和 \(x_n\) 的流量限制,就直接把源点 \(s\) 到 \(1\)、\(1\) 到 \(1'\)、 \(n\) 到 \(n'\)、\(n'\) 到 \(t\)(如果之间有边的话) 的流量设为 \(inf\),然后继续跑最大流,输出即可
当最长不下降子序列为 \(1\) 时,需要特判一下,去重之后才能输出第三个答案,否则答案会变成 \(inf\)
代码
/*
Name: 最长不下降子序列问题
Author: Loceaner
Date: 24/08/20 15:54
*/
#include <queue>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int A = 1e5 + 11;
const int B = 1e6 + 11;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
inline int read() {
char c = getchar();
int x = 0, f = 1;
for ( ; !isdigit(c); c = getchar()) if (c == '-') f = -1;
for ( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
return x * f;
}
struct node { int to, val, nxt; } e[A];
int dep[A], cur[A], head[A], inq[A];
int n, m, s, t, ans = 0, a[A], f[A], cnt = 1;
inline void add(int from, int to, int val) {
e[++cnt].to = to;
e[cnt].val = val;
e[cnt].nxt = head[from];
head[from] = cnt;
}
inline bool bfs() {
queue <int> Q;
for (int i = 1; i <= 2 * n + 2; i++)
cur[i] = head[i], dep[i] = inf, inq[i] = 0;
Q.push(s), dep[s] = 0, inq[s] = 1;
while (!Q.empty()) {
int x = Q.front(); Q.pop(), inq[x] = 0;
for (int i = head[x]; i; i = e[i].nxt) {
int to = e[i].to;
if (dep[to] > dep[x] + 1 && e[i].val) {
dep[to] = dep[x] + 1;
if (!inq[to]) Q.push(to), inq[to] = 1;
}
}
}
if (dep[t] != inf) return 1;
return 0;
}
int dfs(int x, int flow) {
if (x == t) return flow;
for (int i = cur[x], tmp = 0; i; i = e[i].nxt) {
cur[x] = i;
int to = e[i].to;
if (dep[to] == dep[x] + 1 && e[i].val) {
if (tmp = dfs(to, min(e[i].val, flow))) {
e[i].val -= tmp, e[i ^ 1].val += tmp;
return tmp;
}
}
}
return 0;
}
int main() {
n = read(), s = 2 * n + 1, t = 2 * n + 2;
for (int i = 1; i <= n; i++) a[i] = read();
for (int i = 1; i <= n; i++) f[i] = 1;
ans = 1;
for (int i = 2; i <= n; i++)
for (int j = 1; j < i; j++) {
if (a[i] >= a[j]) f[i] = max(f[j] + 1, f[i]);
ans = max(ans, f[i]);
}
cout << ans << '\n';
for (int i = 1; i <= n; i++) {
add(i, i + n, 1), add(i + n, i, 0);
if (f[i] == 1) add(s, i, 1), add(i, s, 0);
if (f[i] == ans) add(i + n, t, 1), add(t, i + n, 0);
for (int j = 1; j < i; j++)
if (a[j] <= a[i] && f[i] == f[j] + 1)
add(j + n, i, 1), add(i, j + n, 0);
}
int now = 0, ans1 = 0;
if (ans == 1) {
cout << n << '\n';
sort(a + 1, a + 1 + n);
int len = unique(a + 1, a + 1 + n) - a - 1;
cout << len << '\n';
return 0;
}
while (bfs()) while (now = dfs(s, inf)) ans1 += now;
cout << ans1 << '\n';
add(s, 1, inf), add(1, s, 0);
add(1, 1 + n, inf), add(1 + n, 1, 0);
if (f[n] == ans)
add(n, n * 2, inf), add(n * 2, n, 0),
add(n * 2, t, inf), add(t, n * 2, 0);;
while (bfs()) while (now = dfs(s, inf)) ans1 += now;
cout << ans1 << '\n';
return 0;
}
转载不必联系作者,但请声明出处