您的位置:首页 > 其它

洛谷 P2764(最小路径覆盖=节点数-最大匹配)

2018-08-23 21:40 423 查看

 

给定有向图G=(V,E)。设P 是G 的一个简单路(顶点不相交)的集合。如果V 中每个顶点恰好在P 的一条路上,则称P是G 的一个路径覆盖。P 中路径可以从V 的任何一个顶点开始,长度也是任意的,特别地,可以为0。G 的最小路径覆盖是G 的所含路径条数最少的路径覆盖。设计一个有效算法求一个有向无环图G 的最小路径覆盖。提示:设V={1,2,.... ,n},构造网络G1=(V1,E1)如下:

每条边的容量均为1。求网络G1的( 0 x , 0 y )最大流。

«编程任务:

对于给定的给定有向无环图G,编程找出G的一个最小路径覆盖。

输入输出格式

输入格式:

 

件第1 行有2个正整数n和m。n是给定有向无环图G 的顶点数,m是G 的边数。接下来的m行,每行有2 个正整数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<=n<=150,1<=m<=6000

由@FlierKing提供SPJ

 

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cmath>
#include<vector>
using namespace std;
#define INF 0x3f3f3f3f
const int maxn = 6e4+10;
int n,m,s,t,u,v;
struct Edge {
int from, to, cap, flow;
};
vector<Edge> edges;
vector<int> G[maxn];
bool vis[maxn];
int d[maxn], cur[maxn],nxt[maxn];

void Init()
{
memset(d,0,sizeof d);
for(int i=0;i<=2*n+1;i++) G[i].clear();
}

void AddEdge(int from, int to, int cap)
{
edges.push_back((Edge){from, to, cap, 0});
edges.push_back((Edge){to, from, 0, 0});
int m = edges.size();
G[from].push_back(m-2); G[to].push_back(m-1);
}

bool bfs()
{
memset(vis,0,sizeof vis);
queue<int> q;
q.push(s);
d[s] = 0; vis[s] = 1;
while (!q.empty())
{
int x = q.front(); q.pop();
for(int i = 0; i < G[x].size(); ++i)
{
Edge &e = edges[G[x][i]];
if (!vis[e.to] && e.cap > e.flow)
{
vis[e.to] = 1;
d[e.to] = d[x] + 1;
q.push(e.to);
}
}
}
return vis[t];
}

int dfs(int x,int a)
{
if(x == t || a == 0) return a;
int flow = 0, f;
for(int &i = cur[x]; i < G[x].size(); ++i)
{
Edge &e = edges[G[x][i]];
if (d[e.to] == d[x] + 1 && (f=dfs(e.to, min(a, e.cap-e.flow))) > 0)
{
e.flow += f;
edges[G[x][i]^1].flow -= f;
flow += f; a -= f;
if (a == 0) break;
}
}
return flow;
}

int MaxFlow(int s, int t)
{
int flow = 0;
while (bfs())
{
memset(cur,0,sizeof cur);
flow += dfs(s, INF);
}
return flow;
}

int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
Init();
for(int i=1;i<=m;i++)
{
scanf("%d%d",&u,&v);
AddEdge(u,v+n,1);
}
s=0,t=2*n+1;
for(int i=1;i<=n;i++)
{
AddEdge(s,i,1);
AddEdge(i+n,t,1);
}
int ans=MaxFlow(s,t);
memset(nxt,0,sizeof nxt);
memset(vis,0,sizeof vis);

for(int i=1;i<=n;i++)
{
for(int j=0;j<G[i].size();j++)
{
Edge &e=edges[G[i][j]];
if(e.flow>0) nxt[e.from]=e.to-n;
}
}
for(int i=1;i<=n;i++)
{
if(!vis[i])
{
int a=i;
vis[a]=1;
printf("%d",a);
while(nxt[a])
{
a=nxt[a];
vis[a]=1;
printf(" %d",a);
}
printf("\n");
}
}
printf("%d\n",n-ans);
}
return 0;
}

  

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐