您的位置:首页 > 其它

poj 3041 Asteroids 最大匹配

2016-04-19 11:56 323 查看
把每一列当成一个点,每一行当成一个点,若行节点和列节点之间有边,则表明该行列该列有一个障碍物。

可以放炸弹炸掉成行或者成列的障碍物!

主要是构图:将每一行当成一个点,构成集合1, 每一列也当成一个点,构成集合2;每一个障碍物的位置坐标将集合1与集合2中的点连接起来,也就是将每一个障碍物作为连接节点的边。这样可以轻易的得出本题是一个最小点覆盖的问题,假设1个行节点覆盖了5个列节点,即这个行节点与这5个列节点间有5条边(即五个障碍物),由于这5条边都被那个行节点覆盖,即表明这5个障碍物都在同一列上,于是可以一颗炸弹全部清除,而本题也就转化成求最小点覆盖数的问题。

又有一个定理是:最小点覆盖数 = 最大匹配数, 所以此题转化成求最大匹配数。

最大匹配算法又称匈牙利算法

//思路:将行看做U集合,列看做V集合,进行增广路的寻找

#include<stdio.h>

#include<string.h>

#define max 10002

int map[502][502];

bool visit[max];

int match[max];

int n;

int path(int start)

{

int i,j;

for(i=1;i<=n;i++) //找从U的某个点与V集合的有关系的点

{

if(visit[i]==false && map[start][i]==1)

{

visit[i]=1; //如果以U的第一个点开始的V的点跟start有关系的话,那么记录

if(match[i]==-1 || path(match[i])) //如果找到的点已经找到匹配的话,那么继续找

{

match[i]=start;

return true;

}

}

}

return false;

}

int main()

{

int m;

scanf("%d%d",&n,&m);

memset(map,0,sizeof(map));

memset(match,-1,sizeof(match));

int i,j;

int a,b;

for(i=1;i<=m;i++)

{

scanf("%d%d",&a,&b);

map[a][b]=1; //有向图

}

int result=0;

for(i=1;i<=n;i++) //从U集合的第一个数字寻找

{

memset(visit,false,sizeof(visit));

if(path(i))

result++;

}

printf("%d\n",result);

return 0;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: