poj3041 匈牙利算法 二分图最大匹配

来源:互联网 发布:好收益网络贷款 编辑:程序博客网 时间:2024/04/29 21:09


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

Hint

INPUT DETAILS:
The following diagram represents the data, where "X" is an asteroid and "." is empty space:
X.X
.X.
.X.


OUTPUT DETAILS:
Bessie may fire across row 1 to destroy the asteroids at (1,1) and (1,3), and then she may fire down column 2 to destroy the asteroids at (2,2) and (3,2).

题意:给出一个方阵,方阵的一些位置标记为X,一次攻击可以消灭一行或者一列的X,那么给出一个方阵,求消灭所有X需要的最少攻击次数。

思路:比赛题,当时只能判断是图论,但是不知道具体做法,看了题解

 分析:这个题目是一个巧妙的二分图建模加上一个定理“二分图最小点覆盖数 = 二分图最大匹配数”。首先简单介绍一下概念,所谓“二分图最小点覆盖”,就是说给出一个二分图,选出能够覆盖全图数目最少的点,而所谓“覆盖”的概念,是在你选择了一个点vi之后,和这个点(当然包括这个点)相连的所有点标记为“已覆盖”。

  那么对于这个题目,我们将n行视作n个元素当成二分图的一个分图,n列视作n个元素当成二分图的一个分图,结合最小点覆盖的概念,你选择一个点,然后覆盖与其相连的所有点的过程,是否就是原题中“消灭一行、或者一列”的过程?这便是建模的关键。

  完成了建模,我们在利用上文提到的定理:  二分图最小点覆盖数 = 二分图最大匹配数。而对于一个二分图求最大匹配数,利用我们已经学过的匈牙利算法即可。关于这个定理的严谨证明,可以参考《算法导论》或者参考网上的资料。

代码:

#include<iostream>#include<fstream>#include<cstring>#include<cstdio>using namespace std;int n, k;int v1, v2;bool Map[501][501];bool visit[501];int link[501];int result;bool dfs(int x){    for (int y = 1; y <= v2; y++)    {        if (Map[x][y] && !visit[y])        {            visit[y] = true;            if (link[y] == 0 || dfs(link[y]))            {                link[y] = x;                return true;            }        }    }    return false;}void Search(){    for (int x = 1; x <= v1; x++)    {        memset(visit,false,sizeof(visit));        if (dfs(x))            result++;    }}int main(){    scanf("%d %d",&n,&k);    v1 = v2 = n;    int x, y;    memset(Map,0,sizeof(Map));    for (int i = 1; i <= k; i++)    {        scanf("%d %d",&x,&y);        Map[x][y] = true;    }    Search();    printf("%d\n",result);    return 0;}


0 0
原创粉丝点击