hdu 3036 Escape 网络流
转载==
题意:每个' . '有一个姑娘, E是出口,'.'是空地 , 'X‘ 是墙。 每秒钟每个姑娘可以走一步(上下左右) 每秒钟每个出口只能出去一个人 给定n*m的地图, 时限T 问所有姑娘能否在T秒内逃生,若能输出最小值,不能输出"impossible" 思路: 显然是二分答案+网络流判可行。 因为每个出口每秒钟只能出去一个人,那么就把每个出口按时间拆点,则T秒钟就拆成T个点。
网络流建图
1、源点 到 每个姑娘 建流量为1的边。 2、若某姑娘到 a出口需要时间为 t秒,则建一条流量为1的边 连向a出口拆点为t秒的点。 3、每个出口的所有拆点向汇点连一条流量为1的边。 4、对于每个出口u的x秒拆点,向u的x+1秒的拆点连一条流量为inf的边(表示从x秒来的人如果x秒还从u出不去,可以在u等到x+1秒出去) 二分一下 第二点中的 t 秒(即答案),判断最大流是否等于人数
#include <stdio.h> #include <iostream> #include <algorithm> #include <sstream> #include <stdlib.h> #include <string.h> #include <limits.h> #include <string> #include <time.h> #include <math.h> #include <queue> #include <stack> #include <set> #include <map> using namespace std; #define INF 0x3f3f3f3f #define eps 1e-8 #define pi acos(-1.0) typedef long long ll; const int maxn=50010; const int maxm=400010; struct Edge{ int to,next,cap; Edge(){}; Edge(int _next,int _to,int _cap){ next=_next;to=_to;cap=_cap; } }edge[maxm]; int head[maxn],tol,dep[maxn],cur[maxn],n; void addedge(int u,int v,int flow){ edge[tol]=Edge(head[u],v,flow);head[u]=tol++; edge[tol]=Edge(head[v],u,0);head[v]=tol++; } int Q[maxn]; bool bfs(int start,int end){ memset(dep,-1,sizeof(dep)); int front=0,rear=0; dep[start]=0;Q[rear++]=start; while(front!=rear){ int u=Q[front++]; for(int i=head[u];i!=-1;i=edge[i].next){ int v=edge[i].to;if(dep[v]==-1&&edge[i].cap){ Q[rear++]=v,dep[v]=dep[u]+1; if(v==end)return 1; } } } return 0; } int dinic(int s,int t){ int i,res=0,top; int S[maxn],cur[maxn]; while(bfs(s,t)){ memcpy(cur,head,sizeof(head)); int u=s;top=0; while(1){ if(u==t){ int min=INF,loc; for(int i=0;i<top;i++)if(min>edge[S[i]].cap) min=edge[S[i]].cap,loc=i; for(int i=0;i<top;i++) edge[S[i]].cap-=min,edge[S[i]^1].cap+=min; res+=min;top=loc;u=edge[S[top]^1].to; } for(int i=cur[u];i!=-1;cur[u]=i=edge[i].next) if(edge[i].cap&&dep[u]+1==dep[edge[i].to])break; if(cur[u]!=-1)S[top++]=cur[u],u=edge[cur[u]].to; else{ if(top==0)break; dep[u]=-1;u=edge[S[--top]^1].to; } } } return res; } char mp[20][20]; int id[20][20],dist[200][200]; int dx[]={0,0,1,-1}; int dy[]={1,-1,0,0}; int main() { // freopen("date.in","r",stdin); //freopen("data.out","w",stdout); int r,c,T; while(~scanf("%d%d%d",&r,&c,&T)){ int girl=0,E=0;memset(id,-1,sizeof(id)); for(int i=0;i<r;i++){ scanf("%s",mp[i]); for(int j=0;j<c;j++){ if(mp[i][j]=='.')girl++; if(mp[i][j]=='E')E++; } } if(!E){ puts("impossible");continue;//没有出口。 } if(!girl){ puts("0");continue;//没有女孩 } int c1=0,c2=0; for(int i=0;i<r;i++) for(int j=0;j<c;j++){ if(mp[i][j]=='.')id[i][j]=(++c1)+E;//女孩编号 if(mp[i][j]=='E')id[i][j]=++c2;//出口编号。 } int flag=1; //cout<<"hhhhh"<<endl; for(int i=0;i<r;i++) for(int j=0;j<c;j++) if(mp[i][j]=='E'){ int s=id[i][j]; for(int k=0;k<160;k++)dist[s][k]=INF; dist[s][s]=0; queue<pair<int,int> > q;q.push(make_pair(i,j)); while(!q.empty()){ pair<int,int> u=q.front();q.pop(); int x=u.first,y=u.second; int gg=id[x][y]; for(int t=0;t<4;t++){ int tx=x+dx[t]; int ty=y+dy[t]; if(tx>=0&&tx<r&&ty>=0&&ty<c&&mp[tx][ty]=='.'){ int dd=id[tx][ty]; if(dist[s][dd]>dist[s][gg]+1){ dist[s][dd]=dist[s][gg]+1; q.push(make_pair(tx,ty)); } } } } } int left=0,right=150; while(left<right){ int mid=(left+right)/2; memset(head,-1,sizeof(head));tol=0; for(int i=E+1;i<=E+girl;i++)//枚举每一个女孩 for(int j=1;j<=E;j++)//枚举每一个出口 if(dist[j][i]<=mid) addedge(i,150+(j-1)*mid+dist[j][i],1); for(int i=E+1;i<=E+girl;i++)addedge(0,i,1);//源点向每一个女孩连流量为1的边 for(int i=1;i<=E;i++) for(int j=1;j<=mid;j++){ addedge(150+(i-1)*mid+j,E*mid+151,1); if(j!=mid) addedge(150+(i-1)*mid+j,150+(i-1)*mid+j+1,INF); } int ans=dinic(0,E*mid+151); if(ans<girl)left=mid+1; else right=mid; } if(left>T){ puts("impossible");continue; } printf("%d\n",left); } return 0; }