11419 SAM I AM(二分图)

很明显的二分图,只是这题需要输出最小覆盖的点

我们可以在求出最大匹配之后,以未覆盖的x点进行标记,沿着未覆盖->覆盖->未覆盖->覆盖...的路径标记,最后S中未标记的和T中标记的点构成最小点覆盖集。

// File Name: 11419.cpp
// Author: zlbing
// Created Time: 2013/3/1 14:20:03

#include<iostream>
#include<string>
#include<algorithm>
#include<cstdlib>
#include<cstdio>
#include<set>
#include<map>
#include<vector>
#include<cstring>
#include<stack>
#include<cmath>
#include<queue>
using namespace std;
#define CL(x,v); memset(x,v,sizeof(x));
#define INF 0x3f3f3f3f
#define LL long long
#define MAXN 1050
int Left[MAXN];
int w[MAXN][MAXN];
bool S[MAXN],T[MAXN];
int N,M;
bool match(int i)
{
    S[i]=true;
    for(int j=1;j<=M;j++)if(w[i][j]&&!T[j])
    {
        T[j]=true;
        if(Left[j]==0||match(Left[j]))
        {
            Left[j]=i;
            return true;
        }
    }
    return false;
}
void dfs(int i)
{
    S[i]=true;
    for(int j=1;j<=M;j++)if(w[i][j]&&!T[j])
    {
        T[j]=true;
        dfs(Left[j]);
    }
}

int main(){
    int t;
    while(~scanf("%d%d%d",&N,&M,&t))
    {
        if(N==0&&M==0&&t==0)break;
        int a,b;
        CL(w,0);
        for(int i=0;i<t;i++)
        {
            scanf("%d%d",&a,&b);
            w[a][b]=1;
        }
        CL(Left,0);
        int sum=0;
        for(int i=1;i<=N;i++)
        {
            CL(S,0);
            CL(T,0);
            if(match(i))sum++;
        }

        bool c[MAXN];
        CL(c,0);
        for(int i=1;i<=M;i++)c[Left[i]]=1;
        CL(S,0);CL(T,0);
        for(int i=1;i<=N;i++)
            if(!c[i])dfs(i);
        printf("%d",sum);
        for(int i=1;i<=N;i++)
            if(!S[i])printf(" r%d",i);
        for(int i=1;i<=M;i++)
            if(T[i])printf(" c%d",i);
        printf("\n");
    }
    return 0;
}
原文地址:https://www.cnblogs.com/arbitrary/p/2938986.html