Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 620 Accepted Submission(s): 136
题目大意:给定一个矩阵,'.'表示空位,'X'表示人,'#'表示墙,'@'表示门,每个位置至多只能站一个人,人不能穿越墙,人能从门中出去。每个人每分钟只能上下左右移动一步,问最少需要多少时间让所有的人出去。
解题思路:二分时间,拆点。第二次做这道题了,还是那么纠结。
#include <string.h> #include <stdio.h> #include <algorithm> #define N 180005 #define E 18000005 #define INF 0x3f3f3f3f #define cha(a,b,c,d) ((a)*m+b+(2*(d)+c)*n*m) using namespace std; int head[N],ed[E],val[E],nxt[E],eid; int n,m,pn,zn,nn; int tu[20][20],vis[20][20]; int tox[5]={0,0,1,-1,0}; int toy[5]={1,-1,0,0,0}; int gap[N],dist[N]; int source,sink; void add_edge(int s,int e,int v,int xv) { ed[eid]=e; nxt[eid]=head[s]; val[eid]=v; head[s]=eid++; ed[eid]=s; nxt[eid]=head[e]; val[eid]=xv; head[e]=eid++; } int dfs(int x,int y) { vis[x][y]=1; if(tu[x][y]==1) return 1; for(int i=0;i<4;i++) { int a=x+tox[i],b=y+toy[i]; if(tu[a][b]<0||vis[a][b])continue; if(dfs(a,b)) return 1; } return 0; } int ifok(void) { for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { if(tu[i][j]!=2)continue; memset(vis,0,sizeof(vis)); if(!dfs(i,j)) return 0; } return 1; } int ISAP(int pos,int cost) { if(pos==sink) return cost; int minh=nn-1,lv=cost; for(int i=head[pos];~i;i=nxt[i]) { int e=ed[i],v=val[i]; if(v>0) { if(dist[e]+1==dist[pos]) { int d=min(v,lv); d=ISAP(e,d); val[i]-=d; val[i^1]+=d; lv-=d; if(dist[source]>=nn)return cost-lv; if(lv==0)break; } minh=min(minh,dist[e]); } } if(lv==cost) { --gap[dist[pos]]; if(gap[dist[pos]]==0)dist[source]=nn; dist[pos]=minh+1; gap[dist[pos]]++; } return cost-lv; } int maxflow(int t) { memset(head,-1,sizeof(head)); eid=0;nn=zn*2*t+2; source=1; sink=cha(0,0,0,t+2); for(int h=1;h<=t;h++) for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { if(tu[i][j]==-1)continue; int a=cha(i,j,0,h); int b=cha(i,j,1,h); add_edge(a,b,1,0); } for(int h=1;h<t;h++) for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { if(tu[i][j]==-1||tu[i][j]==1)continue; int a=cha(i,j,1,h); for(int k=0;k<=4;k++) { int x=i+tox[k],y=j+toy[k]; if(tu[x][y]==-1)continue; int b=cha(x,y,0,h+1); add_edge(a,b,INF,0); } } for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if(tu[i][j]==2) { int b=cha(i,j,0,1); add_edge(source,b,INF,0); } for(int h=1;h<=t;h++) for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if(tu[i][j]==1) { int a=cha(i,j,1,h); add_edge(a,sink,INF,0); } memset(dist,0,sizeof(dist)); memset(gap,0,sizeof(gap)); int ret=0; while(dist[source]<nn) ret+=ISAP(source,INF); return ret; } int main() { while(scanf("%d%d",&n,&m)!=EOF) { memset(tu,-1,sizeof(tu)); pn=0; zn=n*m; for(int i=1;i<=n;i++) { char str[20]; getchar(); scanf("%s",str); for(int j=0;j<m;j++) { if(str[j]=='.') tu[i][j+1]=0; if(str[j]=='@') tu[i][j+1]=1; if(str[j]=='X') tu[i][j+1]=2,pn++; if(str[j]=='#') zn--; } } if(!ifok()) { puts("-1"); continue; } int le=1,ri=n*m,mid; while(ri>le) { mid=(le+ri)/2; if(maxflow(mid)==pn)ri=mid; else le=mid+1; } printf("%d\n",ri-1); } }