[POJ3041]Asteroids

Asteroids

好久没打过网络流相关的题了。。。。。。

题意:一个矩阵n×n,有m个东西,一次去掉一整行或一整列,问最少次数。

题解:匈牙利。
把每行变成一个点(X集合),每列变成一个点(Y集合),每个东西(x,y)连接Xx,Yy,最大匹配即为答案。

证明:对于一行(或一列)的东西,它们都是二分图里的一条边,所以如果这一行有匹配,答案会加1,且这些东西都会被这一行“吞”掉,不会再计入答案。

代码:

// It is made by XZZ
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define rep(a,b,c) for(rg int a=b;a<=c;a++)
#define drep(a,b,c) for(rg int a=b;a>=c;a--)
#define erep(a,b) for(rg int a=fir[b];a;a=nxt[a])
#define il inline
#define rg register
#define vd void
#define t (dis[i])
typedef long long ll;
il int gi(){
    rg int x=0,f=1;rg char ch=getchar();
    while(ch<'0'||ch>'9')f=ch=='-'?-1:f,ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*f;
}
const int maxn=1010,maxm=10100;
int id=0,fir[maxn],dis[maxm],nxt[maxm];
il vd add(int a,int b){nxt[++id]=fir[a],fir[a]=id,dis[id]=b;}
int vis[maxn],match[maxn];
il bool dfs(int now){
    erep(i,now)if(!vis[t]){
	vis[t]=1;
	if(!match[t]||dfs(match[t])){match[t]=now;return 1;}
    }return 0;
}
int main(){
    int n=gi(),a,b,k=gi();
    while(k--)a=gi(),b=gi(),add(a,b+n);
    int ans=0;
    rep(i,1,n)memset(vis,0,sizeof vis),ans+=dfs(i);
    printf("%d\n",ans);
    return 0;
}
posted @ 2017-08-11 14:33  菜狗xzz  阅读(141)  评论(0编辑  收藏  举报