uva11419 【最大二分匹配求最小点覆盖 匈牙利算法】

 uva11419 链接  

    题目大意:给一个由方格组成的二维平面,其中一些平面上有一些 目标需要清理,你可以从每次清理这个矩阵的一行或者一列,问清理位置。

   分析:把点转化为边,就变成求最小点覆盖,而最小点覆盖等于最大二分匹配。(挑程上有证明过程) 用匈牙利算法去求最大二分匹配。

求最小覆盖的步骤大致如下:
1)在右边找到一个未被匹配过的点,标记。
2)走一条没被匹配过的边,到左边的点,标记。
3)走一条匹配过的边到右边,标记。
4)重复2,3步骤直到不能再走。
5)回到步骤一,直到找不到未被匹配且未被标记的右边的点。
6)标记结束后,右边没有标记的点,和左边标记过的点,就可以覆盖所有的边。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
vector<int> g[1010];  //匈牙利算法建的是单向边,一维表x,二维表y。
int luk[1010],visx[1010],visy[1010],n,m,mark[1010],tot;
bool used[1010];
int dfs1(int u)//标记过程
{
    visx[u]=1;
    for(int i=0;i<g[u].size();i++)
    {
        int v=g[u][i];
        if(!visy[v])
        {
            visy[v]=1;
            dfs1(luk[v]);
        }
    }
}
int dfs(int u)//匈牙利算法过程
{
    for(int i=0;i<g[u].size();i++)
    {
        int v=g[u][i];
        if(!used[v])
        {used[v]=1;
        if(luk[v]==-1||dfs(luk[v]))
        {
            luk[v]=u;
            return 1;
        }
        }
    }
    return 0;
}
int erpi()
{
    int res=0;
    memset(luk,-1,sizeof(luk));
    for(int i=1;i<=n;i++)
    {
        memset(used,0,sizeof(used));
        if(dfs(i))res++;
    }
    return res;
}
int main()
{
    int x,y;
    while(scanf("%d%d%d",&n,&m,&tot)!=EOF&&(n||m||tot))
    {
        for(int i=1;i<=n;i++)g[i].clear();
        while(tot--)
        {
            scanf("%d%d",&x,&y);
            g[x].push_back(y);
        }
        int ans=erpi();
        memset(mark,0,sizeof(mark));
        memset(visx,0,sizeof(visx));
        memset(visy,0,sizeof(visy));
        for(int i=1;i<=m;i++)if(luk[i]!=-1)mark[luk[i]]=1;
        for(int i=1;i<=n;i++) if(mark[i]==0)dfs1(i);
        printf("%d",ans);
        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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值