问题描述:
给定有向图G=(V,E)。设P 是G 的一个简单路(顶点不相交)的集合。如果V 中每个顶点恰好在P 的一条路上,则称P是G 的一个路径覆盖。P 中路径可以从V 的任何一个顶点开始,长度也是任意的,特别地,可以为0。G 的最小路径覆盖是G 的所含路径条数最少的路径覆盖。设计一个有效算法求一个有向无环图G 的最小路径覆盖。
编程任务:
对于给定的给定有向无环图G,编程找出G的一个最小路径覆盖。
Input Format
文件第1 行有2个正整数n和m。n是给定有向无环图G 的顶点数,m是G 的边数。接下来的m行,每行有2 个正整数i和j,表示一条有向边(i,j)。
Output Format
从第1 行开始,每行输出一条路径(行末无空格)。文件的最后一行是最少路径数。
网络流经典题,网络流24题之一
题意就是在一个有向无环图里,用最少的路径数覆盖每一个点。
就是如果i,j有一条边,就将i和j+n连一条边,跑一下最大匹配
最少路径条数ans=n-最大匹配数
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define maxn 10005 #define inf 0x7fffff int n,m; int ans; int cnt=1; int to[maxn],head[maxn],q[maxn],h[maxn]; bool mark[maxn]; struct edge{ int next,to,w; }e[2000005]; void ins(int u,int v,int w){ cnt++; e[cnt].next=head[u];e[cnt].to=v;e[cnt].w=w; head[u]=cnt; } void insert(int u,int v,int w){ ins(u,v,w);ins(v,u,0); } bool bfs(){ int t=0,w=1; int now; memset(h,-1,sizeof h); q[0]=h[0]=0; while(t<w){ now=q[t];t++; for(int i=head[now];i;i=e[i].next){ int s=e[i].to; if(e[i].w&&h[s]==-1){ h[s]=h[now]+1; q[w++]=s; } } } if(h[8001]==-1)return 0; return 1; } int dfs(int x,int f){ if(x==8001)return f; int w,used=0; for(int i=head[x];i;i=e[i].next){ int s=e[i].to; if(e[i].w&&h[s]==h[x]+1){ w=f-used; w=dfs(s,min(w,e[i].w)); if(w){ to[x]=s; if(s-n>0)mark[s-n]=1; } e[i].w-=w; e[i^1].w+=w; used+=w; if(used==f)return f; } } if(!used)h[x]=-1; return used; } void dinic(){ while(bfs())ans-=dfs(0,inf); } int main(){ scanf("%d%d",&n,&m); int x,y; for(int i=1;i<=m;i++){ scanf("%d%d",&x,&y); insert(x,n+y,inf); } for(int i=1;i<=n;i++)insert(0,i,1); for(int i=1;i<=n;i++)insert(i+n,8001,1); ans=n; dinic(); for(int i=1;i<=n;i++){ if(mark[i])continue; int k=i; printf("%d ",i); while(to[k]){ printf("%d ",to[k]-n); k=to[k]-n; } printf("\n"); } printf("%d",ans); }
原文地址:https://www.cnblogs.com/Elfish/p/8277464.html
时间: 2024-10-07 12:55:41