HDU 2119 Matrix【二分图之最小点集覆蓋】

原题连接:点击打开链接

题意:给一个矩阵,矩阵点值为0或1,每次可以将矩阵的一行或一列 全变成0 ,问最少需要多少次,可以使矩阵的点全为0.

思路:讲矩阵点值为1的点的横纵座标问边建二分图,求二分图的最小点集覆蓋。

          最小覆蓋要求用最少的点(X集合或Y集合的都行)让每条边都至少和其中一个点关联。可以证明:最少的点(即覆蓋数)=最大匹配数 M
简单的证明如下:
(1)M个是足够的。只需要让它们覆蓋最大匹配的M条边,则其它边一定被覆蓋(如果有边e不被覆蓋,把e加入后得到一个更大的匹配)
(2)M个是必需的,仅考虑形成最大匹配的这M条边,由于它们两两之间没有公共点,因此至少需要M个点才可以把它们覆蓋

代码:

#include<cstdio>
#include<cstring>
#include<queue>
#include<vector>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
vector<int>V[1000];
int link[1000],use[1000];
void init(int n)
{
    int i;
    for(i=0;i<=n;i++)
      V[i].clear();
}
bool Dfs(int v)
{
    int i,j,k;
    for(i=0;i<V[v].size();i++)
    {
        k=V[v][i];
        if(!use[k])
        {
            use[k]=1;
            if(!link[k]||Dfs(link[k]))
            {
                link[k]=v;
                return true;
            }
        }
    }
    return false;
}
int MaxMatch(int n)
{
    int i,j,ans=0;
    memset(link,0,sizeof(link));
    for(i=1;i<=n;i++)
    {
        memset(use,0,sizeof(use));
        if(Dfs(i))
            ans++;
    }
    return ans;

}
int main()
{
    int i,j,n,m,k,t;
    while(scanf("%d",&n)&&n)
    {
        scanf("%d",&m);
        init(n);
        k=0;
        for(i=1;i<=n;i++)
            for(j=1;j<=m;j++)
               {
                   scanf("%d",&t);
                   if(t)
                   {
                       k++;
                       V[i].push_back(j);
                   }
               }
        int ans=MaxMatch(n);
        printf("%d\n",ans);
    }
}
点赞