最多不相交路径
这种问题变化比较多,但都能表示成以下形式:
已知一些路径,每个节点只能属于一条路径,求能选择多少条路径使它们不相交.
主要的方法是拆点,将一个点拆成两个,然后连边,容量表示该点最多经过次数
解题思路:
- 对于第一问:我们直接暴力 d p [ i ] 表 示 以 第 i 个 数 结 尾 的 最 长 不 下 降 子 序 列 的 个 数 就 可 以 求 出 s dp[i]表示以第i个数结尾的最长不下降子序列的个数就可以求出s dp[i]表示以第i个数结尾的最长不下降子序列的个数就可以求出s
- 对于第二问:目的是求出 s s s这种路径有多少条,那么就是典型的最大路径不相交数,因为每个点只能在一个序列里面,那么我们就可以先拆点!!
- 把 x − > [ x , x + n ] ( n 是 数 的 个 数 ) x 是 和 源 点 相 连 , x + n 是 和 汇 点 相 连 x->[x,x+n](n是数的个数)x是和源点相连,x+n是和汇点相连 x−>[x,x+n](n是数的个数)x是和源点相连,x+n是和汇点相连,我们为了求出有多少条那么我们就要保证连向汇点的一定是 d p [ i ] 为 s 的 点 ! dp[i]为s的点! dp[i]为s的点!,而且图上连上汇点的点应该 d p [ i ] 为 1 的 点 dp[i]为1的点 dp[i]为1的点
- 如果 d p [ i ] = d p [ j ] + 1 ( j < i ) dp[i]=dp[j]+1(j<i) dp[i]=dp[j]+1(j<i)那么 从 j + n 向 i 连 边 流 量 为 1 从j+n向i连边流量为1 从j+n向i连边流量为1
- 然后 i 向 i + n 连 流 量 为 1 的 边 i向i+n连流量为1的边 i向i+n连流量为1的边
- 跑最大流的结果就是结果,对于第三问只是我们把 1 1 1和 n n n的所有流量变成 I N F INF INF就好
代码:
#include <bits/stdc++.h>
#define mid ((l + r) >> 1)
#define Lson rt << 1, l , mid
#define Rson rt << 1|1, mid + 1, r
#define ms(a,al) memset(a,al,sizeof(a))
#define log2(a) log(a)/log(2)
#define lowbit(x) ((-x) & x)
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define INF 0x3f3f3f3f
#define LLF 0x3f3f3f3f3f3f3f3f
#define f first
#define s second
#define endl '\n'
using namespace std;
const int N = 2e6 + 10, mod = 1e9 + 9;
const int maxn = 500010;
const long double eps = 1e-5;
const int EPS = 500 * 500;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;
typedef pair<double,double> PDD;
template<typename T> void read(T &x) {
x = 0;char ch = getchar();ll f = 1;
while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}
while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
template<typename T, typename... Args> void read(T &first, Args& ... args) {
read(first);
read(args...);
}
struct node {
int to, next, len;
}e[maxn];
int head[maxn], cnt;
int n, m, s, t;
inline void add(int from, int to, int len) {
e[cnt] = {to,head[from],len};
head[from] = cnt ++;
}
int dp[maxn];
int arr[maxn], num;
int maxs = -1;
int d[maxn],cur[maxn];
int pre[maxn], flow[maxn];
bool bfs() {
ms(d,0);
queue<int> q;
q.push(s); d[s] = 1;
while(!q.empty()) {
int u = q.front(); q.pop();
for(int i = head[u]; ~i; i = e[i].next) {
int v = e[i].to;
if(d[v] || e[i].len <= 0) continue;
q.push(v);
d[v] = d[u] + 1;
}
}
for(int i = 0; i <= n; ++ i) cur[i] = head[i];
return d[t] != 0;
}
int dfs(int u, int flow) {
if(u == t) return flow;
for(int &i = cur[u]; ~i; i = e[i].next) {
int v = e[i].to;
if(d[u] + 1 != d[v] || e[i].len <= 0) continue;
int delta = dfs(v,min(flow,e[i].len));
if(delta <= 0) continue;
e[i].len -= delta;
e[i^1].len += delta;
return delta;
}
return 0;
}
int get_maxflow() {
int maxFlow = 0, delta;
while(bfs())//bfs进行构建最短路网络
while(delta = dfs(s,INF))
maxFlow += delta;
cout << maxFlow << "\n";
if(maxs == 1) {
cout << maxFlow <<"\n";
exit(0);
}
return maxFlow;
}
inline void slove_1() {
for(int i = 1; i <= num; ++ i) dp[i] = 1;
for(int i = 2; i <= num; ++ i)
for(int j = 1; j < i; ++ j)
if(arr[i] >= arr[j])
dp[i] = max(dp[i],dp[j]+1);
for(int i = 1; i <= num; ++ i)
maxs = max(maxs,dp[i]);
cout << maxs << endl;
}
inline void build(int x) {
ms(head,-1), cnt = 0;
for(int i = 1; i <= num; ++ i) {
int flow = 1;
if(i == 1 || i == num) flow = x;
if(dp[i] == 1)
add(s,i,flow), add(i,s,0);
if(dp[i] == maxs)
add(i+num,t,flow), add(t,i+num,0);
}
for(int i = 1; i <= num; ++ i) {
int flow = 1;
if(i == 1 || i == num) flow = x;
add(i,i+num,flow), add(i+num,i,0);
}
for(int i = 1; i <= num; ++ i)
for(int j = 1; j < i; ++ j)
if(arr[i] >= arr[j] && dp[i] == dp[j] + 1) {
add(j+num,i,1);
add(i,j+num,0);
}
}
int main() {
cin >> num;
s = 0, t = num << 1|1;
n = t;
for(int i = 1; i <= num; ++ i) cin >> arr[i];
slove_1();
build(1);
get_maxflow();
build(INF);
get_maxflow();
return 0;
}