[网络流24题]P2764 最小路径覆盖
拆点,最大流
https://www.luogu.com.cn/problem/P2764
题意
给定有向图 \(G=(V,E)\) 。设 \(P\) 是 \(G\) 的一个简单路(顶点不相交)的集合。如果 \(V\) 中每个定点恰好在 \(P\) 的一条路上,则称 \(P\) 是 \(G\) 的一个路径覆盖。\(P\) 中路径可以从 \(V\) 的任何一个定点开始,长度也是任意的,特别地,可以为 \(0\) 。\(G\) 的最小路径覆盖是 \(G\) 所含路径条数最少的路径覆盖。设计一个有效算法求一个 \(DAG,\ G\) 的最小路径覆盖。
Tutorial
每个点原本都是一条路径,如果用边将两个点连接起来,那么就会减少一条路径,这很符合匹配的概念。于是将每个点拆成入点和出点,对于边 \((u,v)\),连接 \((u_出, v_入)\), 显然这是一个二分图。建完图之后跑最大匹配。匹配就代表着选择这条路径。最后再利用link输出路径即可。
经典拆点了。
点击查看代码
#include <bits/stdc++.h>
typedef long long ll;
#define endl '\n'
#define P pair<int, int>
#define eps 1e-8
#define IOS \
ios::sync_with_stdio(0); \
cin.tie(0); \
cout.tie(0);
using namespace std;
const int N = 150 + 5;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
typedef long long ll;
int n, m;
vector<int> mp[N];
int vis[N], link[2][N], pre[N];
int dfs(int u) {
for (auto v : mp[u]) {
if (vis[v])
continue;
vis[v] = 1;
if (link[0][v] == 0 || dfs(link[0][v])) {
link[0][v] = u;
link[1][u] = v;
return 1;
}
}
return 0;
}
int main() {
cin >> n >> m;
for (int i = 0, u, v; i < m; i++) {
cin >> u >> v;
mp[u].push_back(v);
}
for (int i = 1; i <= n; i++) {
memset(vis, 0, sizeof vis);
dfs(i);
}
// for(int i=1;i<=n;i++){
// cout<<i<<": "<<link[1][i]<<" "<<link[0][i]<<endl;
// }
int tot = 0;
memset(vis, 0, sizeof vis);
for (int i = 1; i <= n; i++) {
int o = i, f = 1, flag = 0;
while (o && !vis[o]) {
flag = 1;
cout << o << " ";
vis[o] = 1;
o = link[f][o];
}
if (flag)
flag = 0, tot++, cout << endl;
}
cout << tot;
}

浙公网安备 33010602011771号