• bzoj1189: [HNOI2007]紧急疏散evacuate


    传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=1189

    思路:一种简单的网络流建图:

    预处理两点间距离

    从S向每个空地连1的边,每个空地向它在二分的时间内能到的出口连边,出口在向汇连T的边

    这也是很多题解的做法

    但这是错的...

    当很多人距离门很远时,他们就可能在时间快到时堆在门口出不去,这种建图就忽略了这一点


    所以我们要拆点

    还是二分最大时间T,从S向每个空地连1的边

    把每个门拆成T个点,表示每个时间,由每个点向汇连容量为1的边,表示每个时间只能出去一个人

    然后由时间早的点向后一个时间的点连边,表示可以在门口等待到下一个时间出去

    每个空地向它最早到达这个门的时间所代表的点连1的边

    判断最大流是否等于空地数即可

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    const int dx[]={1,-1,0,0};
    const int dy[]={0,0,1,-1};
    const int maxn=40010,maxm=1000010,inf=(int)1e9;
    using namespace std;
    int n,m,dis[510][510],map[25][25],dor[510],dcnt,blk[510],bcnt,head,tail;char ch[25][25];bool bo[25][25];
    int pre[maxm],now[maxn],son[maxm],val[maxm],tot,di[maxn],S=maxn-2,T=maxn-1,maxt=80;
    struct poi{int x,y;}q[510];
    int id(int x,int y){return (x-1)*m+y;}
    
    void bfs(int sx,int sy){
    	int st=id(sx,sy);
    	memset(dis[st],63,sizeof(dis[st]));
    	memset(bo,0,sizeof(bo));
    	q[tail=1]=(poi){sx,sy};
    	head=0,dis[st][st]=0,bo[sx][sy]=1;
    	while (head!=tail){
    		if (++head>500) head=1;
    		poi a=q[head];
    		for (int i=0;i<4;i++){
    			int nx=a.x+dx[i],ny=a.y+dy[i];
    			
    			if (bo[nx][ny]) continue;
    			if (map[nx][ny]==1){
    				if (++tail>500) tail=1;
    				bo[nx][ny]=1,dis[st][id(nx,ny)]=dis[st][id(a.x,a.y)]+1;
    				q[tail]=(poi){nx,ny};
    			}
    			else if (map[nx][ny]==2)
    				bo[nx][ny]=1,dis[st][id(nx,ny)]=dis[st][id(a.x,a.y)]+1;
    		}
    	}
    }
    
    void init(){
    	for (int i=1;i<=n;i++)
    		for (int j=1;j<=m;j++)
    			if (map[i][j]==1) bfs(i,j),blk[++bcnt]=id(i,j);
    			else if (map[i][j]==2) dor[++dcnt]=id(i,j);
    }
    struct Tflow{
    	int q[maxn+10],head,tail;
    	int id(int x,int tim){return (x-1)*maxt+tim+bcnt;}
    	void add(int a,int b,int c){pre[++tot]=now[a],now[a]=tot,son[tot]=b,val[tot]=c;}
    	void ins(int a,int b,int c){add(a,b,c),add(b,a,0);}
    	void clear(){memset(now,0,sizeof(now)),tot=1;}
    	bool bfs(){
    		memset(di,-1,sizeof(di));
    		q[1]=S,di[S]=0,head=0,tail=1;
    		while (head!=tail){
    			if (++head>maxm) head=1;
    			int x=q[head];
    			for (int y=now[x];y;y=pre[y])
    				if (di[son[y]]==-1&&val[y]){
    					if (++tail>maxm) tail=1;
    					di[son[y]]=di[x]+1,q[tail]=son[y];
    				}
    		}
    		return di[T]>0;
    	}
    	int find(int x,int low){
    		if (x==T) return low;
    		int y,res=0;
    		for (y=now[x];y;y=pre[y]){
    			if (!val[y]||di[son[y]]!=di[x]+1) continue;
    			int tmp=find(son[y],min(low,val[y]));
    			val[y]-=tmp,val[y^1]+=tmp,res+=tmp,low-=tmp;
    			if (!low) break;
    		}
    		if (!y) di[x]=-1;
    		return res;
    	}
    	bool dinic(int lim){
    		int res=0;clear();
    		for (int i=1;i<=bcnt;i++) ins(S,i,1);
    		for (int i=1;i<=dcnt;i++) for (int j=1;j<=lim;j++){
    			ins(id(i,j),T,1);
    			if (j>1) ins(id(i,j-1),id(i,j),inf);
    		}
    		for (int i=1;i<=bcnt;i++)
    			for (int j=1;j<=dcnt;j++){
    				int x=blk[i],y=dor[j];
    				if (dis[x][y]<=lim) ins(i,id(j,dis[x][y]),1);
    			}
    		while (bfs()) res+=find(S,inf);
    		return res==bcnt;
    	}
    }Ts;
    
    void work(){
    	int l=1,r=n*m,mid=(l+r)>>1,ans=-1;
    	while (l<=r){
    		if (Ts.dinic(mid)) r=mid-1,ans=mid;
    		else l=mid+1;
    		mid=(l+r)>>1;
    	}
    	if (ans==-1) puts("impossible");
    	else printf("%d
    ",ans);
    }
    
    int main(){
    	scanf("%d%d",&n,&m);
    	for (int i=1;i<=n;i++) scanf("%s",ch[i]+1);
    	for (int i=1;i<=n;i++)
    		for (int j=1;j<=m;j++)
    			if (ch[i][j]=='D') map[i][j]=2;
    			else if (ch[i][j]=='.') map[i][j]=1;
    	init(),work();
    	return 0;
    }


  • 相关阅读:
    pycharm设置linux中的python解析器进行本地开发
    linux安装python
    Jenkins自动构建的几种方式
    接口加密
    python接口自动化—unittest 常用的断言方法
    cookie 组成结构
    post请求的四种数据格式
    jmeter之数据库相关
    jmeter函数简介
    java_第一年_JDBC(6)
  • 原文地址:https://www.cnblogs.com/thythy/p/5493465.html
Copyright © 2020-2023  润新知