UVa 11419 二分图最小点覆盖

来源:互联网 发布:小型鱼缸制冷机淘宝 编辑:程序博客网 时间:2024/04/29 04:00

The world is in great danger!! Mental’s forces have returned toEarth to eradicate humankind. Our last hope to stop this greatevil is Sam “Serious” Stone. Equipped with various powerfulweapons, Serious Sam starts his mission to destroy the forces ofevil.After fighting two days and three nights, Sam is now in front ofthe temple KOPTOS where Mental’s general Ugh Zan III is waitingfor him. But this time, he has a serious problem. He is in shortageof ammo and a lot of enemies crawling inside the temple waitingfor him. After rounding the temple Sam finds that the temple isin rectangle shape and he has the locations of all enemies in thetemple.All of a sudden he realizes that he can kill the enemies without entering the temple using the greatcannon ball which spits out a gigantic ball bigger than him killing anything it runs into and keeps onrolling until it finally explodes. But the cannonball can only shoot horizontally or vertically and all theenemies along the path of that cannon ball will be killed.Now he wants to save as many cannon balls as possible for fighting with Mental. So, he wants toknow the minimum number of cannon balls and the positions from which he can shoot the cannonballsto eliminate all enemies from outside that temple.InputThe input file contains several test cases.Here, the temple is defined as a R × C grid. The first line of each test case contains 3 integers:R (0 < R < 1001), C (0 < C < 1001) representing the grid of temple (R means number of row andC means number of column of the grid) and the number of enemies N (0 < N < 1000001) inside thetemple. After that there are N lines each of which contains 2 integers representing the position ofthe enemies in that temple. Each test case is followed by a new line (except the last one). Input isterminated when R = C = N = 0.OutputFor each test case there will be one line output. First print the minimum number (m) of cannonballsneeded to wipe out the enemies followed by a single space and then m positions from which he canshoot those cannonballs. For shooting horizontally print ‘r’ followed by the row number and for verticalshooting print ‘c’ followed by the column number. If there is more than one solution any one will do.Sample Input4 4 31 11 43 24 4 21 12 20 0 0Sample Output2 r1 r32 r1 r2


题目大意:一个r*c的图里面有N个目标,每次可以消灭一排或者一列,问最少攻击几次能消灭所有目标

二分图最小点覆盖问题,将所有点的x,y分别为两个集合,点为连线,每次攻击都是一行或者一列,那么就是攻击一个x或者一个y,也就只要求出最小多少个x或者能覆盖所有边就行了

拿第一组样例

x集里面有1,3,  y集合里面有1,2,4  点(1,1)为1和1的边(1,4)是1和4的边(3,2)是3和2的边

最小覆盖点集就是r1和c2;

网上只有König定理的证明并没有给出具体的代码

自己摸索着写的时间级好高


#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>#include<string>#include<map>#include<set>#include<queue>#include<stack>#include<cstdlib>#define INF 0x7fffffff#define EPS 1e-12#define MOD 1000000007#define PI 3.141592653579798#define P ((sqrt(5.0)+1.0)/2.0)#define PP (sqrt(5.0)-1)/2using namespace std;typedef long long  ll;int mm[1001][1001];int vis[1001],dis[1001];int have[1010],r[1010],c[1010],le[1100],ri[1100];int n,m,N;int dfs(int v){    for(int u=1;u<=m;u++){        if(mm[v][u]&&!vis[u]){            vis[u]=1;            if(dis[u]==-1||dfs(dis[u])){                dis[u]=v;                return 1;            }        }    }    return 0;}void ko(int fl,int v){    if(fl){        r[v]=1;        le[v]=1;        for(int i=1;i<=m;i++){            if(dis[i]==v&&!ri[i]){                ko(0,i);            }        }    }    else {        c[v]=1;        ri[v]=1;        for(int i=0;i<=n;i++){            if(mm[i][v]&&!le[i]){                ko(1,i);            }        }    }}int main(){    while(cin>>n>>m>>N&&(n+m+N)){        memset(mm,0,sizeof(mm));        memset(dis,-1,sizeof(dis));        for(int i=0;i<=1000;i++){            have[i]=0;            r[i]=0;            c[i]=0;        }        for(int i=0;i<N;i++){            int x,y;            scanf("%d%d",&x,&y);            mm[x][y]=1;            have[y]=1;        }        int sum=0;        for(int i=1;i<=n;i++){            memset(vis,0,sizeof(vis));            if(dfs(i)){                sum++;            }        }        for(int i=1;i<=m;i++){            if(dis[i]==-1&&have[i]){                memset(le,0,sizeof(le));                memset(ri,0,sizeof(ri));                ko(0,i);            }        }        cout<<sum;        for(int i=1;i<=m;i++){            if(have[i]&&!c[i]){                printf(" c%d",i);            }        }        for(int i=1;i<=n;i++){            if(r[i]){                printf(" r%d",i);            }        }        cout<<endl;    }    return 0;}



0 0
原创粉丝点击