【网络流24题】最小路径覆盖问题
Description
给定有向图G=(V,E)。设P是G的一个简单路(顶点不相交)的集合。如果V中每个顶点恰好在P的一条路上,则称P是G的一个路径覆盖。P中路径可以从V的任何一个顶点开始,长度也是任意的,特别地,可以为0。G的最小路径覆盖是G的所含路径条数最少的路径覆盖。
设计一个有效算法求一个有向无环图G的最小路径覆盖。
Input
第1行有2个正整数n和m。n是给定有向无环图G的顶点数,m是G的边数。
接下来的m行,每行有2个正整数i 和j,表示一条有向边(i,j)。
Output
第1行开始,每行输出一条(字典序)路径。最后一行是最少路径数。
Sample Input
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
Sample Output
1 4 7 10 11
2 5 8
3 6 9
3
Hint
数据范围:
1<=n<=150,1<=m<=6000
提示:
设V={1,2,... ,n},构造网络G1=(V1,E1)如下:
每条边的容量均为1。求网络G1的(x0,y0)最大流。
一道巨坑题。。。这是链接【只有COGS支持SPJ,我也是呵呵了】
思路:既然每个点只能经过一次,不妨把一个点拆成A、B两点,对原图中a->b的边,连接a.A->b.B,跑一遍匈♂牙利,酱紫之后就可以发现点数-匹配数==剩下点数(废话),一条路径可以解决一堆剩下的点,于是ans=n-匹配数
1 // It is made by XZZ 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #define File 6 #define Fname "path3" 7 using namespace std; 8 #define rep(a,b,c) for(rg int a=b;a<=c;a++) 9 #define drep(a,b,c) for(rg int a=b;a>=c;a--) 10 #define erep(a,b) for(rg int a=fir[b];a;a=nxt[a]) 11 #define il inline 12 #define rg register 13 #define vd void 14 #define t (dis[i]) 15 typedef long long ll; 16 il int gi(){ 17 rg int x=0;rg char ch=getchar(); 18 while(ch<'0'||ch>'9')ch=getchar(); 19 while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar(); 20 return x; 21 } 22 const int maxn=151<<1,maxm=6002; 23 int id=0,fir[maxn],dis[maxm],nxt[maxm]; 24 il vd add(int a,int b){ 25 nxt[++id]=fir[a],fir[a]=id,dis[id]=b; 26 } 27 inline bool BFS() { 28 int bfs[maxn]; 29 memset(dep,0,sizeof dep); 30 bfs.push(S); 31 bool yes[600]= {0}; 32 yes[S]=1,dep[S]=0; 33 while(!bfs.empty()) { 34 int now=bfs.front(); 35 for(int i=fir[now]; i; i=nxt[i]) 36 if(w[i]>0&&!yes[t]) 37 yes[t]=1,bfs.push(t),dep[t]=dep[now]+1; 38 bfs.pop(); 39 } 40 return yes[T]; 41 } 42 int dep[maxn]; 43 inline int Dinic(int now,int h) { 44 if(now==T)return h; 45 int ans=0; 46 for(int i=fir[now]; i; i=nxt[i]) 47 if(w[i]>0&&dep[t]==dep[now]+1) { 48 int D=Dinic(t,min(h,w[i])); 49 w[i]-=D,w[i^1]+=D,ans+=D,h-=D; 50 if(h==0)return ans; 51 } 52 return ans; 53 } 54 int main(){ 55 freopen(Fname".in","r",stdin); 56 freopen(Fname".out","w",stdout); 57 rg int n=gi(),m=gi(); 58 while(m--){rg int i=gi(),j=gi();add(i,j+n);} 59 memset(match,-1,sizeof match); 60 int ans=0; 61 drep(i,n,1){ 62 memset(vis,0,sizeof vis); 63 vis[i]=1;if(dfs(i))++ans; 64 } 65 drep(i,n+n,n+1)if(match[i]+1)to[match[i]]=i-n,in[i-n]=1; 66 rep(i,1,n)if(!in[i]){ 67 int now=i;printf("%d ",now); 68 while(to[now])now=to[now],printf("%d ",now); 69 puts(""); 70 } 71 printf("%d ",n-ans); 72 return 0; 73 }