bzoj2547 玩具兵 bfs&最大匹配

       在lrj的某一本书(蓝书?紫书?黑书?我不知道>_<)里面看到过。

       首先可以把交换看成是更改职业,那么二分答案x,我们就得到了每个玩具兵(不包括天兵)可以到达的目标格。那么连一条边就得到一个二分图,跑最大匹配即可。

       注意不能直接判断是否有完美匹配,还要考虑天兵,因为我们可以让天兵到x个地方然后作x次交换,那么在跑最大匹配的时候不把天兵加进去,然后判断是否有最大匹配数+x>=n即可。

AC代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
#define N 115
#define M 1005
using namespace std;

const int dx[4]={-1,1,0,0},dy[4]={0,0,-1,1};
int m,n,cnt,pt,tot,c[N][N],d[N][N],path[N],mp[N][N];
struct node{ int x,y; }a[N],b[N],h[M+5]; bool bo[N],inq[N][N];
void bfs(int sx,int sy,int p){
	memset(d,0x3f,sizeof(d)); d[sx][sy]=0;
	int i,t,head=0,tail=1; node u,v;
	h[1].x=sx; h[1].y=sy; memset(inq,0,sizeof(inq));
	while (head!=tail){
		head=head%M+1; u=h[head]; inq[u.x][u.y]=0;
		for (i=0; i<4; i++){
			v.x=u.x+dx[i]; v.y=u.y+dy[i];
			if (v.x<=0 || v.x>m || v.y<=0 || v.y>n) continue;
			if (p^(d[u.x][u.y]&1))
				if (c[v.x][v.y]<=c[u.x][u.y]) t=0; else t=1;
			else
				if (c[v.x][v.y]>=c[u.x][u.y]) t=0; else t=1;
			if (d[u.x][u.y]+t<d[v.x][v.y]){
				d[v.x][v.y]=d[u.x][u.y]+t;
				if (!inq[v.x][v.y]){ inq[v.x][v.y]=1; tail=tail%M+1; h[tail]=v; }
			}
		}
	}
}
bool dfs(int x,int lim){
	int i;
	for (i=1; i<=tot; i++) if (bo[i] && mp[x][i]<=lim){
		bo[i]=0;
		if (!path[i] || dfs(path[i],lim)){
			path[i]=x; return 1;
		}
	}
	return 0;
}
bool ok(int x){
	int i,tmp=0; memset(path,0,sizeof(path));
	for (i=1; i<=(cnt<<1); i++){
		memset(bo,1,sizeof(bo));
		if (dfs(i,x)) tmp++;
	}
	return tmp+x>=(cnt<<1);
}
int main(){
	scanf("%d%d%d%d",&m,&n,&cnt,&pt); int i,j,x,y,t;
	for (i=1; i<=(cnt<<1|1); i++) scanf("%d%d",&a[i].x,&a[i].y);
	for (i=1; i<=pt; i++){
		scanf("%d%d%d",&x,&y,&t);
		while (t--){ b[++tot].x=x; b[tot].y=y; }
	}
	for (i=1; i<=m; i++)
		for (j=1; j<=n; j++) scanf("%d",&c[i][j]);
	for (i=1; i<=(cnt<<1); i++){
		if (i<=cnt) bfs(a[i].x,a[i].y,0); else bfs(a[i].x,a[i].y,1);
		for (j=1; j<=tot; j++) mp[i][j]=d[b[j].x][b[j].y];
	}
	int l=0,r=cnt<<1,mid;
	while (l<r){
		mid=(l+r)>>1;
		if (ok(mid)) r=mid; else l=mid+1;
	}
	printf("%d\n",l);
	return 0;
}


by lych

2016.4.6

你可能感兴趣的:(bfs,二分,最大匹配)