您的位置:首页 > 其它

PKU 3041 Asteroids - 行列的二分图模型 最小点覆盖

2008-11-21 22:37 453 查看
题目大意:

N*N的空间中有K个小行星,使用超级武器可以一次性清理一行或一列的所有小行星.但是超级武器很贵,给出星空图,问最少需要使用多少次武器能清除所有的小行星.N<500, k<10,000

分析:

很经典的行列模型转换为二分图模型来处理的题目,ZJU1002和PKU2226也是可以这样转换.

将行和列分别作为二分图左边和右边的节点.若在地图(i,j)上有一颗小行星,那么二分图左边i节点和右边j节点之间连一条边.

将此模型对应到题目上来,使用一次武器就是选择二分图上左边或右边的一个点v.和v相连的边,表示v行(或列)当中所有的小行星.那么题目的问题转换为了:在二分图中选择最少的点,使得所有的边都至少有一个端点被覆盖到.

这就是经典的二分图的最小点覆盖.

根据König定理:二分图 最小点覆盖数 = 最大匹配数.

所以题目转换为了求二分图的最大匹配,也就比较完美的解决了.

顺便说一句,ZJU1002的二分图模型的不能直接用行或列作为二分图的点,而是需要拆点.详细请看我的另一篇解题报告

http://blog.csdn.net/tiaotiaoyly/archive/2008/10/23/3122893.aspx

/*

PKU3041 Asteroids

*/

#include <stdio.h>

#include <memory.h>

#define clr(a) memset(a,0,sizeof(a))

#define N 505

int find(int i,int m,int g[]
,int mat[],int tmat[]){

int v,j;

for(j=0;j<m;j++){

if(g[i][j]&&tmat[j]==0){

tmat[j]=1; v=mat[j]; mat[j]=i;

if(v==-1||find(v,m,g,mat,tmat)) return 1;

mat[j]=v;

}

}

return 0;

}

int match(int g[]
,int n,int m,int mat[]){

int i,k=0,tmat
;

for(i=0;i<m;i++) mat[i]=-1;

for(i=0;i<n;i++){

clr(tmat); k+=find(i,m,g,mat,tmat);

}

return k;

}

int n,m;

int a

;

int mat
;

int main()

{

int i,j,k;

while(scanf("%d%d",&n,&m)!=EOF){

//init

clr(a);

//input

for(k=0;k<m;k++){

scanf("%d%d",&i,&j);

i--; j--;

a[i][j]=1;

}

//output

k=match(a,n,n,mat);

printf("%d/n",k);

}

return 0;

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