BZOJ 1189: [HNOI2007]紧急疏散evacuate|网络流|二分答案

S连“。”流量为1

二分答案 x

算出每一个门到每一个点的距离若小于x连边 流量为1

门连T 流量为 x

其实这个题完全不用拆点

因为门限制的流量为x   

若有x个点和门的dis<x  

每个点到门的距离肯定<=x

而且dis=x的点最多有一个

#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<iostream>
#include<algorithm>
#define T 99999
using namespace std;
int dx[]={0,0,-1,1};
int dy[]={-1,1,0,0};
int t[T];
int head[444],nxt[T],lst[T],v[T];
int id[33][33],mx[444],my[444];
int dis[33][33],q[T][2],S,W,h[T];
char s[33][33];int D[444];
int n,m,tot=1,cnt,top,pl,sum;
void insert(int x,int y,int z)
{
	//cout << x <<" "<< y <<" "<< z << endl;
	lst[++tot]=y; nxt[tot]=head[x]; head[x]=tot; v[tot]=z;
	lst[++tot]=x; nxt[tot]=head[y]; head[y]=tot; v[tot]=0;
}
void bfs(int xx,int yy,int f)
{
	memset(dis,0,sizeof(dis));
	int l=1,r=2; q[1][0]=xx,q[1][1]=yy;
	while(l<r)
	{
		int x=q[l][0],y=q[l++][1];
		for(int i=0;i<4;i++)
		{
			int nx=x+dx[i],ny=y+dy[i];
			if(s[nx][ny]=='.')
			{
				if(!dis[nx][ny])
				{
					dis[nx][ny]=dis[x][y]+1;
					if(dis[nx][ny]<=f)
					{
						q[r][0]=nx,q[r++][1]=ny;
					    insert(id[nx][ny],id[xx][yy],1);
					}
				}
			}
		}
	}
}
bool BFS()
{
	for(int i=1;i<=W;i++)D[i]=0;D[S]=1;
	int l=1,r=2;h[1]=S;
	while(l<r)
	{
		int x=h[l++];
		for(int i=head[x];i;i=nxt[i])
		    if(v[i]>0&&!D[lst[i]])
		    {
		    	D[lst[i]]=D[x]+1;
		    	h[r++]=lst[i];
		    }
    }
    return D[W]!=0;
}
int dfs(int x,int f)
{
	int ww=0,w;
	if(x==W)return f;
	for(int i=head[x];i;i=nxt[i])
	    if(v[i]&&D[lst[i]]==D[x]+1)
	    {
	    	w=dfs(lst[i],min(v[i],f-ww));
	    	ww+=w;v[i]-=w,v[i^1]+=w;
	    	if(f==ww)return ww;
	    }
	return ww;
}	
bool jud(int x)
{
	memset(head,0,sizeof(head));tot=1;
	for(int i=1;i<=top;i++)bfs(mx[i],my[i],x);
	//system("pause");
	for(int i=1;i<=n;i++)
	    for(int j=1;j<=m;j++)
		    if(s[i][j]=='.')insert(S,id[i][j],1);
	for(int i=1;i<=top;i++)insert(id[mx[i]][my[i]],W,x);
	int ans=0;
	while(BFS())ans+=dfs(S,T);
	return ans==sum;
}
		
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)scanf("%s",s[i]+1);
	for(int i=1;i<=n;i++)
	    for(int j=1;j<=m;j++)
	        if(s[i][j]!='X')
	        {
	            id[i][j]=++cnt;
	            if(s[i][j]=='D')
	            {
	            	mx[++top]=i;
	            	my[top]=j;
	            }
	        }
	S=cnt+1,W=S+1;
	for(int i=1;i<=n;i++)
	    for(int j=1;j<=m;j++)
	        if(s[i][j]=='.')sum++;
	int l=0,r=sum,ans=0;
	while(l<=r)
	{
		int mid=(l+r)>>1;
		if(jud(mid))ans=mid,r=mid-1;
		else l=mid+1;
	}
	if(!ans)printf("impossible");
	else cout << ans;
}


你可能感兴趣的:(网络流)