poj 2594 Treasure Exploration 最小路径覆盖
题目链接:http://poj.org/problem?id=2594
建图很重要!!!
大致题意:
给出一个由n个顶点m条边组成的有向无环图。求最少可以同时存在多少路径,使得这些路径可以覆盖所有的点(注:每个点可以被多条路径覆盖)。
大致思路:
最小路径覆盖的一点小小变形,由于这里的点可以被重复覆盖,所以除了按照普通求最小路径覆盖的方式建立二分图以外,还要对原图用floyd求一遍传递闭包,并更新二分图。接下来用点数n减去最大匹配得到的就是答案
【最小路径覆盖(原图不一定是二分图,但必须是有向图,拆点构造二分图)】:在图中找一些路径,使之覆盖了图中的所有顶点,且任何一个顶点有且只有一条路径与之关联。最小路径覆盖 = |V| - 最大匹配数
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 using namespace std; 5 const int MAX=515; 6 int map[MAX][MAX]; 7 int visit[MAX]; 8 int use[MAX]; 9 int n,m; 10 int solve(int x) 11 { 12 int j; 13 for(j=1;j<=n;j++) 14 { 15 if(map[x][j]&&!visit[j]) 16 { 17 visit[j]=1; 18 if(use[j]==-1||solve(use[j])) 19 { 20 use[j]=x; 21 return 1; 22 } 23 } 24 } 25 return 0; 26 } 27 int match() 28 { 29 int i,count=0; 30 for(i=1;i<=n;i++) 31 { 32 memset(visit,0,sizeof(visit)); 33 if(solve(i))count++; 34 } 35 return count; 36 } 37 void floyd()//本题的顶点可以被覆盖多次所以要对原图进行传递闭包 38 { 39 int i,j,k; 40 for(k=1;k<=n;k++) 41 for(i=1;i<=n;i++) 42 for(j=1;j<=n;j++) 43 if(map[i][k]&&map[k][j]) 44 map[i][j]=1; 45 } 46 int main() 47 { 48 int x,y,i,j; 49 while(scanf("%d%d",&n,&m)&&(n+m)) 50 { 51 memset(use,-1,sizeof(use)); 52 memset(map,0,sizeof(map)); 53 54 for(j=1;j<=m;j++) 55 { 56 scanf("%d%d",&x,&y); 57 map[x][y]=1; 58 } 59 floyd(); 60 x=match(); 61 printf("%d\n",n-x); 62 } 63 return 0; 64 }