最小路径覆盖问题可以转化为最大二分图匹配问题
现在已知 G(V,E) G ( V , E ) ,求最小路径覆盖,做法:
可以发现除去 源汇点 的 N(V′,E′) N ( V ′ , E ′ ) 就是二分图
求出 N(V′,E′) N ( V ′ , E ′ ) 的 max_flow(s,t),那么最小路径覆盖 = |V|− | V | − max_flow(s,t)
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
//#include
//#include
#include
using namespace std;
#define mp make_pair
#define pb push_back
#define se second
#define fi first
#define rep(i, n) for(int i = 0; i < n; ++i)
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
typedef long double ldb;
typedef pair<int, int> pii;
const int MOD = (int)1e9 + 7;
const int INF = 0x3f3f3f3f;
const ll LL_INF = 0x3f3f3f3f3f3f3f3f;
const db PI = acos(-1.0);
const db EPS = 1e-10;
const int MAXV = 405;
const int MAXE = 6005 * 3;
int V, E;
struct edge{
int to, cap, cost, nxt;
edge() {}
edge(const int _to, const int _cap, const int _nxt) {
to = _to;
cap = _cap;
nxt = _nxt;
}
}dat[MAXE<<1];
int head[MAXV], tail;
void add_edge(int from, int to, int cap) {
dat[tail] = edge(to, cap, head[from]);
head[from] = tail++;
dat[tail] = edge(from, 0, head[to]);
head[to] = tail++;
}
int level[MAXV], iter[MAXV];
queue<int> que;
void bfs(int s, int t) {
memset(level, 0xff, sizeof(int) * (t + 1));
level[s] = 1;
que.push(s);
while(!que.empty()) {
int u = que.front(); que.pop();
for(int v = head[u]; ~v; v = dat[v].nxt) {
edge &e = dat[v];
if(level[e.to] < 0 && e.cap > 0) {
level[e.to] = level[u] + 1;
que.push(e.to);
}
}
}
}
int dfs(int u, int t, int f) {
if(u == t) return f;
for(int &v = iter[u]; ~v; v = dat[v].nxt) {
edge &e = dat[v];
if(e.cap > 0 && level[e.to] > level[u]) {
int d = dfs(e.to, t, min(f, e.cap));
if(d > 0) {
e.cap -= d;
dat[v^1].cap += d;
return d;
}
}
}
return 0;
}
int max_flow(int s, int t) {
int res = 0, f;
while(true) {
bfs(s, t);
if(level[t] < 0) return res;
memcpy(iter, head, sizeof(int) * (t + 1));
while((f = dfs(s, t, INF)) > 0) res += f;
}
return res;
}
int par[MAXV], ru[MAXV];
int norml(int x) {return (x - 1) % V + 1;}
void print_path(int s, int t) {
for(int i = 0; i <= V; ++i) par[i] = i;
for(int i = 1; i <= V; ++i) {
for(int v = head[i]; ~v; v = dat[v].nxt) {
if(dat[v].cap == 0 && dat[v].to != s && dat[v].to != t) {
par[norml(i)] = norml(dat[v].to);
++ru[par[norml(i)]];
}
}
}
for(int i = 1; i <= V; ++i) if(!ru[i]) {
for(int v = i; ; v = par[v]) {
printf(par[v] == v ? "%d\n" : "%d ", v);
if(v == par[v]) break;
}
}
}
int main()
{
scanf("%d%d", &V, &E);
int s = 0, t = V * 2 + 1;
memset(head, 0xff, sizeof(int) * (t + 1));
tail = 0;
for(int i = 1; i <= V; ++i) {
add_edge(s, i, 1);
add_edge(i + V, t, 1);
}
for(int i = 0; i < E; ++i) {
int x, y;
scanf("%d%d", &x, &y);
add_edge(x, y + V, 1);
}
int cnt = V - max_flow(s, t);
print_path(s, t);
printf("%d\n", cnt);
return 0;
}
给定有向图 G=(V,E)。设 P 是 G 的一个简单路(顶点不相交)的集合。如果 V 中每个顶点恰好在 P 的一条路上,则称 P 是 G 的一个路径覆盖。P 中路径可以从 V 的任何一个顶点开始,长度也是任意的,特别地,可以为 0。G 的最小路径覆盖是 G 的所含路径条数最少的路径覆盖。
设计一个有效算法求一个有向无环图 G 的最小路径覆盖。
第 1 行有 2 个正整数 n 和 m。 n 是给定有向无环图 G 的顶点数,m 是 G 的边数。
接下来的 m 行,每行有 2 个正整数 u 和 v,表示一条有向边 (i,j) ( i , j ) 。
从第 1 1 1 行开始,每行输出一条路径。
文件的最后一行是最少路径数。
样例
样例输入
11 12
1 2
1 3
1 4
2 5
3 6
4 7
5 8
6 9
7 10
8 11
9 11
10 11
样例输出
1 4 7 10 11
2 5 8
3 6 9
3
数据范围与提示
1≤n≤200,1≤m≤6000 1 ≤ n ≤ 200 , 1 ≤ m ≤ 6000