受下列文章启发:
http://kukumayas.iteye.com/blog/1075610
http://blog.csdn.net/lyy289065406/article/details/6646007
把每一行每一列都当成一个节点来看待,把每个外星人的坐标当成一条边看待,
这样就可以把问题转化成求“最小点覆盖”,由于K?nig定理,再转换成求“最大二分图匹配”,
于是就可以用匈牙利算法。匈牙利算法有一个核心概念就是找增广路,如果有增广路,
则匹配加一,而找增广路的核心就是一个交差树的概念。
至于增广路和二分图以及二分图匹配,交差树的概念上面两个链接地址的文章多看看应该就能领悟了。
(个人IQ比较低,看了大概两三个小时的样子才明白)
由于用dfs来实现找增广路较bfs来说形式上更加简洁,所以这道题的求增广路是否存在采用dfs来做,
第一个链接里的模拟就是dfs找增广路的模拟。
下面是我的代码,以及一些注释,这是我第一次写匈牙利算法,所以详细地写了一些注释,供大家参考。
#include<iostream> #include<cstring> using namespace std; int link[510],num_dian;//link用来存放已经连通的点,由于这里二分图的两个子图的顶点数相同,所以统一用num_dian来存放顶点数 bool map[510][510],visit[510];//map用来存放可存在的边,visit的作用是在dfs中避免搜索起始点陷入死循环,搜索中访问过的点就进行标记(我这里把每一行当作起始点,当然每一列也是可以的) bool dfs(int x) { int i; for(i=1;i<=num_dian;i++) { if(map[x][i]==1&&visit[i]==0)//如果x-i边可连同且i点没有被访问 { visit[i]=1;//访问此点,并标记 if(link[i]==0||dfs(link[i])==1)//如果i点未被连同,或者通过dfs实现以当前i的连通点为起点交差树搜索是否有尚未连通的点加入 { link[i]=x;//连同i,x两点 return 1;//返回1表示可以增加一个新的匹配 } } } return 0;//返回0表示此时无法增加一个新的匹配 } int xiongyali() { int i,sum; sum=0; for(i=1;i<=num_dian;i++)//从一个子图的点(这里是代表每一行的点)出发,找是否还能够匹配,也就是找增广路 { memset(visit,0,sizeof(visit)); if(dfs(i)) sum++; } return sum; } int main() { int n,k,i,row,line,sum; memset(map,0,sizeof(map)); memset(link,0,sizeof(link)); scanf("%d%d",&n,&k); num_dian=n; for(i=0;i<k;i++) { scanf("%d%d",&row,&line); map[row][line]=1; } printf("%d\n",xiongyali()); }
原文地址:http://blog.csdn.net/stl112514/article/details/28611097