受下列文章启发:
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