题目描述
给定有向图 G=(V,E)G=(V,E) 。设 PP 是 GG 的一个简单路(顶点不相交)的集合。如果 VV 中每个定点恰好在PP的一条路上,则称 PP 是 GG 的一个路径覆盖。PP中路径可以从 VV 的任何一个定点开始,长度也是任意的,特别地,可以为 00 。GG 的最小路径覆盖是 GG 所含路径条数最少的路径覆盖。设计一个有效算法求一个 GAP (有向无环图) GG 的最小路径覆盖。
提示:设 V=\{1,2,...,n\}V={1,2,...,n} ,构造网络 G_1=\{V_1,E_1\}G1={V1,E1} 如下:
V_1=\{x_0,x_1,...,x_n\}\cup\{y_0,y_1,...,y_n\}V1={x0,x1,...,xn}∪{y0,y1,...,yn}
E_1=\{(x_0,x_i):i\in V\}\cup\{(y_i,y_0):i\in V\}\cup\{(x_i,y_j):(i,j)\in E\}E1={(x0,xi):i∈V}∪{(yi,y0):i∈V}∪{(xi,yj):(i,j)∈E}
每条边的容量均为 11 ,求网络 G_1G1 的 (x_0,y_0)(x0,y0) 最大流。
输入输出格式
输入格式:
第一行有 22 个正整数 nn 和 mm 。 nn 是给定\text{GAP}GAP(有向无环图) GG 的顶点数, mm 是 GG 的边数。接下来的 mm 行,每行有两个正整数 ii 和 jj 表示一条有向边 (i,j)(i,j)。
输出格式:
从第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:
1 4 7 10 11
2 5 8
3 6 9
3
说明
1\leq n\leq 150,1\leq m\leq 60001≤n≤150,1≤m≤6000
由@FlierKing提供SPJ
解题思路
依旧是拆点转化成二分图然后dinic(),然后dfs输出路径。
代码如下
#include <iostream>
#include <vector>
#include <cstring>
#include <cmath>
#include <queue>
#define INF 0x3f3f3f3f
#define s 0
#define t 310
using namespace std;
vector<int> g[355];
struct Line{
int r, w;
bool dir;
Line(int r, int w, bool dir): r(r), w(w), dir(dir){ }
};
vector<Line> line;
void add_line(int x, int y)
{
line.push_back(Line(y, 1, 1));
g[x].push_back(line.size() - 1);
line.push_back(Line(x, 0, 0));
g[y].push_back(line.size() - 1);
}
int deep[355];
bool bfs()
{
queue<int> que;
memset(deep, 0, sizeof(deep));
que.push(s);
deep[s] = 1;
while(!que.empty()){
int top = que.front();
que.pop();
for(int i = 0; i < g[top].size(); i ++){
int z = g[top][i];
if(!deep[line[z].r] && line[z].w){
deep[line[z].r] = deep[top] + 1;
que.push(line[z].r);
if(deep[t])
return true;
}
}
}
return false;
}
int dfs(int x, int mix)
{
if(!mix || x == t)
return mix;
int ap = 0;
for(int i = 0; i < g[x].size(); i ++){
int z = g[x][i];
if(deep[x] < deep[line[z].r] && line[z].w){
int p = dfs(line[z].r, min(mix, line[z].w));
mix -= p;
ap += p;
line[z].w -= p;
line[z^1].w += p;
if(!mix)
return ap;
}
}
return ap;
}
int dinic()
{
int ans = 0;
while(bfs())
ans += dfs(s, INF);
return ans;
}
bool vis[155];
void dfs2(int x)
{
for(int i = 0; i < g[x].size(); i ++){
int z = g[x][i];
if(!vis[line[z].r / 2] && line[z].dir && !line[z].w){
vis[line[z].r / 2] = true;
cout << " " << line[z].r / 2;
dfs2(line[z].r - 1);
}
}
}
int main()
{
int n, m;
while(cin >> n >> m){
for(int i = 1; i <= n; i ++){
add_line(s, 2*i);
add_line(2*i+1, t);
}
for(int i = 0; i < m; i ++){
int x, y;
cin >> x >> y;
add_line(2*x, 2*y+1);
}
int sum = dinic();
memset(vis, 0, sizeof(vis));
for(int i = 1; i <= n; i ++){
if(!vis[i]){
vis[i] = true;
cout << i;
dfs2(2 * i);
cout << endl;
}
}
cout << n - sum << endl;
for(int i = 0; i <= t; i ++)
g[i].clear();
line.clear();
}
}