UVa:11419 SAM I AM

来源:互联网 发布:十进制转bcd码算法 编辑:程序博客网 时间:2024/06/15 20:05

行为左边点集,列为右边点集,障碍为边,这样消灭所有障碍即每条边都连着一个点。这样选最少的点即可。这样问题就是求解最小点覆盖集,在二分图中等价于二分最大匹配。但是这里还要求出最小点覆盖集。方法是,在求出二分图最大匹配后,寻找左边点中的未盖点进行拓展匈牙利树,将所有遍历到的点标记。这样左边中为标记的,右边的标记的点即为最小点覆盖集。

#include <iostream>#include <cstdio>#include <cstring>#include <string>#include <cmath>#include <vector>#include <queue>#include <map>#include <algorithm>#define ll long long#define INF 1e30#define inf -2139062144#define MOD 20071027#define MAXN 1005using namespace std;bool gl[MAXN][MAXN];bool visy[MAXN],visx[MAXN];int link[MAXN];int R,C,N;int flagx[MAXN],flagy[MAXN];bool match(int x){    flagx[x]=true;    for(int i=1; i<=C; ++i)        if(!visy[i]&&gl[x][i])        {            visy[i]=true;            flagy[i]=true;            if(link[i]==-1||match(link[i]))            {                link[i]=x;                return true;            }        }    return false;}int main(){    while(scanf("%d%d%d",&R,&C,&N))    {        if(!R&&!C&&!N) break;        memset(link,-1,sizeof(link));        memset(gl,0,sizeof(gl));        memset(visx,0,sizeof(visx));        for(int i=0; i<N; ++i)        {            int x,y;            scanf("%d%d",&x,&y);            gl[x][y]=true;        }        int ans=0;        for(int i=1; i<=R; ++i)        {            memset(visy,0,sizeof(visy));            if(match(i)) ans++;        }        memset(flagx,0,sizeof(flagx));        memset(flagy,0,sizeof(flagy));        printf("%d",ans);        for(int i=1; i<=C; ++i)            visx[link[i]]=true;        for(int i=1; i<=R; ++i)        {            memset(visy,0,sizeof(visy));            if(!visx[i]) match(i);        }        for(int i=1; i<=R; ++i)            if(!flagx[i]) printf(" r%d",i);        for(int i=1; i<=C; ++i)            if(flagy[i]) printf(" c%d",i);        printf("\n");    }    return 0;}


 

0 0
原创粉丝点击