uva 11419(最小点覆盖 二分图匹配 + 输出最小点覆盖集)

题意: 你现在有n+m  个大炮,  现在在一个n*m的网格中有 c  个敌人 每一个大炮一发子弹可以干掉一行的敌人 或者一列的敌人

问你最少需要几发炮弹。  将大炮看成点  分为行点  和列点  ,每个敌人看成是边  那么就可以抽象成  用最少的点去覆盖 所有的边

二分图的最大匹配等于最小点覆盖。 但是这里要输出 最小点覆盖集  。。  方法是从  行点  所有没有被覆盖的点 出发扩展 匈牙利树。匈牙利树其实是匹配边和为匹配边的交替。 这样跑出来之后  行点对应的没有访问过的点和 列点访问过得点就是最小点覆盖集。

#include<bits/stdc++.h>

using namespace std;
const int N =1005;
int boy[N],girl[N];

vector< int >ve[N]; // 单向建边
int vis1[N];
int vis2[N];
int n,m,c;

int dfs(int x)
{
    vis1[x]=1;
    for(int i=0;i<ve[x].size();i++)
    {
        int v=ve[x][i];
        if(!vis2[v]){
            vis2[v]=1;
            if(dfs(girl[v])||girl[v]==-1)
            {
                girl[v]=x;
                boy[x]=v;
                return 1;
            }
        }
    }
    return 0;
}

void xiongyali()
{
    memset(boy,-1,sizeof(boy));
    memset(girl,-1,sizeof(girl));
    int cnt=0;
    for(int i=1;i<=n;i++)
    {
        memset(vis2,0,sizeof(vis2));
        if(dfs(i)) cnt++;
    }

    cout<<cnt;

    memset(vis1,0,sizeof(vis1));
    memset(vis2,0,sizeof(vis2));

    for(int i=1;i<=n;i++)
    {
        if(boy[i]==-1){
            dfs(i);
        }
    }
    for(int i=1;i<=n;i++){
        if(vis1[i]==0){
            printf(" r%d",i);
        }
    }

    for(int i=1;i<=m;i++){
        if(vis2[i]){
            printf(" c%d",i);
        }
    }
    return ;
}

int main()
{
    int u,v;
    while(cin>>n>>m>>c)
    {
        for(int i=1;i<=n;i++) ve[i].clear();
        if(n==0&&m==0&&c==0) break;
        while(c--)
        {
            scanf("%d %d",&u,&v);
            ve[u].push_back(v);
        }
        xiongyali();
        printf("\n");
    }
    return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值