POJ 2594 Treasure Exploration(传递闭包+最小路径覆盖)

//传递闭包的建立(Floyd) + 最小路径覆盖 //这题有别于1422,原因在于它是一个有向图,而非DAG,机器人可以绕一圈回来在走其他路 //the roads of two different robots may contain some same point. //例如1->2,2->3,3->4,4->2,2->5这一个有向图,这个图只要1个机器人就可以走完所有路,但如果不建立传递闭包 //直接根据边进行匹配,那样得出来的结果是不正确的,因为平时所指的路径覆盖,顶点最多只经过一次,而这道题是可以经过多次的 //因此必须用floyd重新确定连通性,建立一个传递闭包,根据这个闭包建立新的图,使得满足每个顶点只经过一次 //这样再用二分图最大匹配的方法求最小路径覆盖就可以了 #include<iostream> using namespace std; const int MAX = 502; int N,M; bool A[MAX][MAX]; int X,Y,vis[MAX],G[MAX][MAX],yMatch[MAX]; void floyd()//求传递闭包并建立新图 { for(int k = 1;k <= N;++k) for(int i = 1;i <= N;++i) for(int j = 1;j <= N;++j) { if(i == j) continue; if(A[i][k] && A[k][j]) A[i][j] = 1; } for(int i = 1;i <= N;++i) for(int j = 1;j <= N;++j) if(A[i][j]) G[i][j] = 1; } bool findPath(int x)//寻找增广路 { for(int y = 1;y <= Y;++y) { if(!vis[y] && G[x][y]) { vis[y] = 1; if(yMatch[y] == -1 || findPath(yMatch[y]))//如果v未被匹配或者v找到新的增广路 { yMatch[y] = x; return true; } } } return false; } int maxMatch()//返回最大匹配数 { int ans = 0; memset(yMatch,-1,sizeof(yMatch));//初始化 for(int x = 1;x <= X;++x)//注意编号的不同 { memset(vis,0,sizeof(vis)); if(findPath(x)) ++ans; } return ans; } int main() { int x,y; while(scanf("%d%d",&N,&M) && N) { memset(A,0,sizeof(A)); memset(G,0,sizeof(G)); while(M--) { scanf("%d%d",&x,&y); A[x][y] = 1; } floyd(); X = Y = N; printf("%d/n",X - maxMatch()); } return 0; } 

你可能感兴趣的:(POJ 2594 Treasure Exploration(传递闭包+最小路径覆盖))