uva 11419 最大匹配(最小点覆盖)

链接:https://vjudge.net/problem/27475

题意:给定一个二维矩阵,在一些格子里放置了东西,然后你有一门炮,每次能横向或纵向开一炮,将这一行所有的东西摧毁。问你最少花多少炮弹摧毁所有的东西?并输出一组解。

题解:

  很久之前做的题目了,今天在看到的时候还是很有新的体会的。这是一个求最小覆盖的问题,最小点覆盖,将行列的每个点看作是x,y集合,将放置的东西的地方看作是边(大白书)。然后求一次最大匹配,会得出来至少有多个点是不在同一行和同一列的,这样剩余的东西就会与原来的已匹配的点在同一行或者同一列,求完最大匹配后,可以得出开枪的次数,然后进行求方案数。从未匹配的点开始拓展,第一次没有参与匹配的点 在哪一行最多 或者在哪一列最多 那么肯定开枪位置就在这一行 或者这一列,这里的左右集合表现的很明显,因为记录 路径的缘故。

参考代码:

#include <stdio.h>
#include <algorithm>
#include <math.h>
#include <string.h>
#include <vector>
#include <queue>
#include <stack>
#include <iostream>
#define INF 0x3f3f3f3f
using namespace std;
const int maxn=1011;
int mp[maxn][maxn];
int machl[maxn],machr[maxn],visx[maxn],visy[maxn];
int n,m,k;
bool dfs(int u)
{
    visx[u]=1;
    for(int i=1;i<=m;i++)
        if(!visy[i]&&mp[u][i])
        {
            visy[i]=true;
            if(machr[i]==-1||dfs(machr[i]))
            {
                machl[u]=i;//列匹配
                machr[i]=u;//行匹配
                return true;
            }
        }
    return false;
}
int Maxmach()
{
    int ans=0;
    memset(machl,-1,sizeof(machl));
    memset(machr,-1,sizeof(machr));
    for(int i=1;i<=n;i++)
    {
        memset(visy,0,sizeof(visy));
        if(dfs(i))
            ans++;
    }
    return ans;
}
int  main()
{
    //freopen("C:\\Users\\Administrator\\Desktop\\a.txt","r",stdin);
    int a,b;
    while(scanf("%d%d%d",&n,&m,&k),n+m+k)
    {
        memset(mp,0,sizeof(mp));
        for(int i=0;i<k;i++)
            scanf("%d%d",&a,&b),mp[a][b]=1;
        int Ans=Maxmach();
        printf("%d",Ans);


        //求方案数

        memset(visx,0,sizeof(visx));
        memset(visy,0,sizeof visy);
        for(int i=1;i<=n;i++)  //从x中未匹配的点出发
            if(machl[i]==-1) dfs(i);
        for(int i=1;i<=n;i++)
            if(!visx[i]) printf(" r%d",i);
        for(int i=1;i<=m;i++)
            if(visy[i]) printf(" c%d",i);
        printf("\n");
    }
    return 0;
}

 

  

posted @ 2017-09-25 16:45  MeowMeowMeow  阅读(214)  评论(0编辑  收藏  举报