POJ-3041 Asteroids(最大匹配)

来源:互联网 发布:八零网络验证1.3下载 编辑:程序博客网 时间:2024/06/05 14:30

A - Asteroids
Time Limit:1000MS     Memory Limit:65536KB     64bit IO Format:%lld & %llu
Submit Status

Description

Bessie wants to navigate her spaceship through a dangerous asteroid field in the shape of an N x N grid (1 <= N <= 500). The grid contains K asteroids (1 <= K <= 10,000), which are conveniently located at the lattice points of the grid. 

Fortunately, Bessie has a powerful weapon that can vaporize all the asteroids in any given row or column of the grid with a single shot.This weapon is quite expensive, so she wishes to use it sparingly.Given the location of all the asteroids in the field, find the minimum number of shots Bessie needs to fire to eliminate all of the asteroids.

Input

* Line 1: Two integers N and K, separated by a single space. 
* Lines 2..K+1: Each line contains two space-separated integers R and C (1 <= R, C <= N) denoting the row and column coordinates of an asteroid, respectively.

Output

* Line 1: The integer representing the minimum number of times Bessie must shoot.

Sample Input

3 41 11 32 23 2

Sample Output

2

解题思路:

把方阵看做一个特殊的二分图(以行列分别作为两个顶点集V1V2,其中| V1|=| V2|

然后把每行x或者每列y看成一个点,而障碍物(x,y)可以看做连接xy的边。按照这种思路构图后。问题就转化成为选择最少的一些点(xy),使得从这些点与所有的边相邻,其实这就是最小点覆盖问题。

 

再利用二分图最大匹配的König定理:

最小点覆盖数 = 最大匹配数

 

PS:最小点覆盖:假如选了一个点就相当于覆盖了以它为端点的所有边,你需要选择最少的点来覆盖图的所有的边。)

 

因此本题自然转化为求 二分图的最大匹配 问题

 

 

求最大匹配的一种显而易见的算法是:先找出全部匹配,然后保留匹配数最多的。但是这个算法的时间复杂度为边数的指数级函数

因此,需要寻求一种更加高效的算法——增广路求最大匹配的方法(匈牙利算法)

 

增广路的定义(也称增广轨或交错轨)

P是图G中一条连通两个未匹配顶点的路径,并且属于M的边和不属于M的边(即已匹配和待匹配的边)P上交替出现,则称P为相对于M的一条增广路径。

 

 由增广路的定义可以推出下述三个结论:

  1P的路径个数必定为奇数,第一条边和最后一条边都不属于M

2、将MP进行取反操作可以得到一个更大的匹配M’

   (反操作:把P中的 匹配边  非匹配边 互换)

3MG的最大匹配当且仅当不存在M的增广路径P

 

 匈牙利算法轮廓:

  (1)M为空

  (2)找出一条增广路径P,通过异或操作获得更大的匹配M’代替M

(3)重复(2)操作直到找不出增广路径为止

#include<stdio.h>#include<string.h>#include<stdlib.h>#include<queue>#include<math.h>#include<limits.h>#include<algorithm>using namespace std;#define maxn 1005#define maxs 505int box[maxs][maxs];int map[maxs][maxs];int ans[maxn];int link[maxn];int n,k;int dfs(int x){for(int i=1;i<=n;i++){if(map[x][i] && !ans[i]){ans[i]=1;if(link[i]==-1 || dfs(link[i])){link[i]=x;return 1; } }}return 0;}int  main(){while(scanf("%d%d",&n,&k)!=EOF){int sum=0;int a,b;    memset(link,-1,sizeof(link));memset(map,0,sizeof(map));for(int i=1;i<=k;i++)  {  scanf("%d%d",&a,&b);  map[a][b]=1;  }for(int i=1;i<=n;i++){memset(ans,0,sizeof(ans));int t=dfs(i);if(t)   sum++;}printf("%d\n",sum);}} 

0 0