版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_36616023/article/details/82927096
题目描述
«问题描述:
给定有向图G=(V,E)。设P 是G 的一个简单路(顶点不相交)的集合。如果V 中每个顶点恰好在P 的一条路上,则称P是G 的一个路径覆盖。P 中路径可以从V 的任何一个顶点开始,长度也是任意的,特别地,可以为0。G 的最小路径覆盖是G 的所含路径条数最少的路径覆盖。设计一个有效算法求一个有向无环图G 的最小路径覆盖。
«编程任务:
对于给定的给定有向无环图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<algorithm>
#include<string>
#include<cstring>
using namespace std;
const int maxn=400000;
const int maxm=160000;
const int inf=0x3f3f3f3f;
struct edge
{
int v,w,nxt;
}edge[maxm*4];
int head[maxn],cnt;
void add_edge(int u,int v,int w)
{
edge[cnt].v=v;
edge[cnt].w=w;
edge[cnt].nxt=head[u];
head[u]=cnt++;
edge[cnt].v=u;
edge[cnt].w=0;
edge[cnt].nxt=head[v];
head[v]=cnt++;
}
int numh[maxn],h[maxn],curedge[maxn],pre[maxn];
int sap(int s,int t,int n)
{
memset(numh,0,sizeof(numh));
memset(h,0,sizeof(h));
memset(pre,-1,sizeof(pre));
int cur_flow,flow_ans=0,u,tmp,neck,i;
for(i=1;i<=n;i++)
{
curedge[i]=head[i];
}
numh[0]=n;
u=s;
while(h[s]<n)
{
if(u==t)
{
cur_flow=inf;
for(i=s;i!=t;i=edge[curedge[i]].v)
{
if(cur_flow>edge[curedge[i]].w)
{
neck=i;
cur_flow=edge[curedge[i]].w;
}
}
for(i=s;i!=t;i=edge[curedge[i]].v)
{
tmp=curedge[i];
edge[tmp].w-=cur_flow;
edge[tmp^1].w+=cur_flow;
}
flow_ans+=cur_flow;
u=neck;
}
for(i=curedge[u];i!=-1;i=edge[i].nxt)
{
if(edge[i].w&&h[u]==h[edge[i].v]+1)
{
break;
}
}
if(i!=-1)
{
curedge[u]=i;
pre[edge[i].v]=u;
u=edge[i].v;
}
else
{
if(0==--numh[h[u]])
break;
curedge[u]=head[u];
for(tmp=n,i=head[u];i!=-1;i=edge[i].nxt)
{
if(edge[i].w)
{
tmp=min(tmp,h[edge[i].v]);
}
}
h[u]=tmp+1;
++numh[h[u]];
if(u!=s)
u=pre[u];
}
}
return flow_ans;
}
int vis[maxn];
int path[maxn];
int mid=0;
void dfs(int u,int n)
{
if(u>n)
return;
path[++mid]=u;
for(int i=head[u];i!=-1;i=edge[i].nxt)
{
if(vis[edge[i].v]==0)
{
if(edge[i].w==0)
{
if(edge[i].v>n)
{
vis[edge[i].v-n]=1;
dfs(edge[i].v-n,n);
}
else
{
vis[edge[i].v]=1;
}
}
}
}
}
int main ()
{
int n,m;
scanf("%d%d",&n,&m);
int S,T;
S=2*n+1;
T=S+1;
memset(vis,0,sizeof(vis));
memset(head,-1,sizeof(head));
cnt=0;
for(int i=1;i<=n;i++)
{
add_edge(S,i,1);
add_edge(i+n,T,1);
}
for(int i=1;i<=m;i++)
{
int xx,yy;
scanf("%d%d",&xx,&yy);
add_edge(xx,yy+n,1);
}
int ans=sap(S,T,T);
for(int i=1;i<=n;i++)
{
mid=0;
if(vis[i]==0)
{
dfs(i,n);
printf("%d",path[1]);
for(int j=2;j<=mid;j++)
{
printf(" %d",path[j]);
}
printf("\n");
}
}
printf("%d\n",n-ans);
}