P1356 -- 8-3 最小路径覆盖问题
时间限制:1000MS
内存限制:131072KB
Description
给定有向图G=(V,E)。设P 是G 的一个简单路(顶点不相交)的集合。如果V 中每个顶点恰好在P 的一条路上,则称P是G 的一个路径覆盖。P 中路径可以从V 的任何一个顶点开始,长度也是任意的,特别地,可以为0。G 的最小路径覆盖是G 的所含路径条数最少的路径覆盖。设计一个有效算法求一个有向无环图G 的最小路径覆盖。
Input Format
第1 行有2个正整数n和m。n是给定有向无环图G 的顶点数,m是G 的边数。接下来的m行,每行有2 个正整数i和j,表示一条有向边(i,j)。
Output Format
从第1 行开始,每行输出一条路径(行末无空格,有空格你就wa了)。文件的最后一行是最少路径数。
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
n<=150 m<=6000
【题解】
最小路径覆盖可以用二分图匹配/网络流来做。
具体的就是若从A到B有路径,连A,B+n即可。
然后匈牙利搞一搞就好了。
1 #include <stdio.h> 2 #include <string.h> 3 using namespace std; 4 5 const int V=500,E=70010; 6 int n,m; 7 bool vis[V]; 8 int fa[V],head[V],to[E],next[E],ans=0; 9 10 bool hungry(int u) { 11 for (int i=head[u];i;i=next[i]) { 12 if(!vis[to[i]]) { 13 vis[to[i]]=1; 14 if(!fa[to[i]]||hungry(fa[to[i]])) { 15 fa[to[i]]=u; 16 fa[u]=to[i]; 17 return 1; 18 } 19 } 20 } 21 return 0; 22 } 23 24 inline int g() { 25 int x=0,f=1;char ch=getchar(); 26 while(ch<'0'||ch>'9') { 27 if(ch=='-') f=-1; 28 ch=getchar(); 29 } 30 while(ch>='0'&&ch<='9') { 31 x=(x<<1)+(x<<3)+ch-'0'; 32 ch=getchar(); 33 } 34 return x*f; 35 } 36 37 int main() { 38 n=g(),m=g(); 39 for (int i=1,a,b;i<=m;++i) { 40 a=g(),b=g(); 41 to[i]=b+n; 42 next[i]=head[a]; 43 head[a]=i; 44 } 45 for (int i=1;i<=n;++i) { 46 if(fa[i]) continue; 47 memset(vis,0,sizeof(vis)); 48 if(hungry(i)) ++ans; 49 } 50 memset(vis,0,sizeof(vis)); 51 for (int i=1;i<=n;++i) { 52 if(!vis[i]) { 53 vis[i]=1; 54 printf("%d",i); 55 for (int j=fa[i];j;j=fa[j-n]) { 56 printf(" %d",j-n); 57 vis[j-n]=1; 58 } 59 printf(" "); 60 } 61 } 62 printf("%d ",n-ans); 63 return 0; 64 }