题意:
每一个' . '有一个姑娘, 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 秒(即答案),推断最大流是否等于人数
二分匹配建图:
枚举时间(由于时间最大仅仅有12*12)
在原图的基础上加上以下的边:
在i时间内若能出去则那姑娘向全部能出去的 出口时间拆点连边。
再在原来的匹配上继续增广,累计最大匹配数。
当最大匹配数==人数时则是最小的时间。
数据较水能够用点非主流的建图卡过去,预计仅仅有30组数据。
网络流代码:
#include<stdio.h> #include<string.h> #include<iostream> #include<algorithm> #include<queue> #include<vector> using namespace std; #define ll int #define N 20050 #define M 105000 #define inf 10737418 struct Edge{ ll from, to, cap, nex; }edge[M*4];//注意这个一定要够大 不然会re 还有反向弧 ll head[N], edgenum; void add(ll u, ll v, ll cap){ Edge E = { u, v, cap, head[u]}; edge[ edgenum ] = E; head[u] = edgenum ++; Edge E2= { v, u, 0, head[v]}; edge[ edgenum ] = E2; head[v] = edgenum ++; } ll sign[N]; bool BFS(ll from, ll to){ memset(sign, -1, sizeof(sign)); sign[from] = 0; queue<ll>q; q.push(from); while( !q.empty() ){ int u = q.front(); q.pop(); for(ll i = head[u]; i!=-1; i = edge[i].nex) { ll v = edge[i].to; if(sign[v]==-1 && edge[i].cap) { sign[v] = sign[u] + 1, q.push(v); if(sign[to] != -1)return true; } } } return false; } ll Stack[N], top, cur[N]; ll dinic(ll from, ll to){ ll ans = 0; while( BFS(from, to) ) { memcpy(cur, head, sizeof(head)); ll u = from; top = 0; while(1) { if(u == to) { ll flow = inf, loc;//loc 表示 Stack 中 cap 最小的边 for(ll i = 0; i < top; i++) if(flow > edge[ Stack[i] ].cap) { flow = edge[Stack[i]].cap; loc = i; } for(ll i = 0; i < top; i++) { edge[ Stack[i] ].cap -= flow; edge[Stack[i]^1].cap += flow; } ans += flow; top = loc; u = edge[Stack[top]].from; } for(ll i = cur[u]; i!=-1; cur[u] = i = edge[i].nex)//cur[u] 表示u所在能增广的边的下标 if(edge[i].cap && (sign[u] + 1 == sign[ edge[i].to ]))break; if(cur[u] != -1) { Stack[top++] = cur[u]; u = edge[ cur[u] ].to; } else { if( top == 0 )break; sign[u] = -1; u = edge[ Stack[--top] ].from; } } } return ans; } void init(){memset(head,-1,sizeof head);edgenum = 0;} char mp[15][15]; int n, m, T; int Hash(int x,int y){return x*m+y;} vector<int>E,P; int dis[150][150], step[4][2]={1,0,-1,0,0,1,0,-1}; bool vis[150][150]; void bfs(int sx,int sy){ int start = Hash(sx,sy); memset(vis, 0, sizeof vis); vis[sx][sy] = 1; dis[start][start] = 0; queue<int>qx,qy; while(!qx.empty())qx.pop(); while(!qy.empty())qy.pop(); qx.push(sx), qy.push(sy); while(!qx.empty()){ int x = qx.front(), y = qy.front(); qx.pop(); qy.pop(); for(int i = 0; i < 4; i++){ int dx = x + step[i][0], dy = y + step[i][1]; if(!(0<=dx&&dx<n&&0<=dy&&dy<m))continue; if(vis[dx][dy] || mp[dx][dy]!='.')continue; vis[dx][dy] = 1; dis[Hash(dx,dy)][start] = dis[start][Hash(dx,dy)] = dis[start][Hash(x,y)]+1; qx.push(dx); qy.push(dy); } } } bool ok(int TIME){ init(); int from = N-2, to = N-1; for(int i = 0; i < P.size(); i++)add(from, P[i], 1); for(int i = 0; i < P.size(); i++) { for(int j = 0; j < E.size(); j++) if(dis[P[i]][E[j]]<=TIME) add(P[i],j*150+150+dis[P[i]][E[j]],1); } for(int i = 0; i < E.size(); i++) for(int j = 1; j <= TIME; j++) { add(i*150+150+j, to, 1); if(j!=TIME) add(i*150+150+j,i*150+150+j+1,inf); } return dinic(from,to)==P.size(); } int main(){ //freopen("date.in","r+",stdin); //freopen("ans.out","w+",stdout); int i, j; while(~scanf("%d %d %d",&n,&m,&T)){ E.clear(); P.clear(); memset(dis, 0, sizeof dis); memset(mp, 0, sizeof mp); for(i=0;i<n;i++)scanf("%s",mp[i]); for(i=0;i<n;i++)for(j=0;j<m;j++) { if(mp[i][j]=='E')E.push_back(Hash(i,j)); else if(mp[i][j]=='.')P.push_back(Hash(i,j)); } if(P.size()==0){puts("0");continue;} if(E.size()==0){puts("impossible");continue;} for(i = 0; i < E.size(); i++)bfs(E[i]/m, E[i]%m); int l = 1, r = 256, ans = inf; while(l<=r) { int mid = (l+r)>>1; if(ok(mid))ans = min(ans, mid), r = mid-1; else l = mid+1; } if(T<ans || ans==inf){puts("impossible");continue;} else printf("%d\n",ans); } return 0; } /* 6 12 100000 ......E....E E.EEE...E... ...E....EE.. .E.E.......E .....E...... .E...E...EE. 11 3 100000 X.. ... .E. EE. E.E ... ... .E. E.. ..E E.. 7 6 100000 .E..E. ...E.. ...... ...E.E ...X.. ...EE. ....E. 11 10 100000 .E........ ......E... ........E. EE....E..E ...E...E.. ......XE.E .......... .........X .........E .EE....... ..EE.E.E.E 7 3 100000 ... ..E ... ..X EE. ... .X. 3 2 100000 .. .. EE 6 7 100000 ..E.... ....... .....E. ...EE.. ....... ....... 6 8 100000 ..EEEE.. ...E.... ........ ........ .......E E......E 10 8 100000 E.E..X.. ........ E...E... E..E.... ........ .....E.. ......EX ........ .E...... ..E..EE. 5 5 100 ..... XXXXX EEEEE ..... XXXXX 1 1 1 E 1 1 1 P 1 1 1 X 2 2 1 E. .X 2 2 2 E. .X 8 1 1000 . E . . . . . . 3 4 100 E... .... ...E 3 4 100 E... .E.. ...E 4 5 100 E.... .E... ...E. ..... 4 5 100 ..... .E... ..... ..... 12 12 10000000 ...E.....E.E E.E.E.....E. .......E.... ............ ......E..... ............ ...E.....E.E E.E.E.....E. .......E.... ............ ......E..... ............ 12 12 6 ...E.....E.E E.E.E.....E. .......E.... ............ ......E..... ............ ...E.....E.E E.E.E.....E. .......E.... ............ ......E..... ............ 12 12 10000000 E........... ............ ............ ............ ............ ............ ............ ............ ............ ............ ............ ............ 12 12 10000000 E........... ............ ............ ............ ............ .....E...... ............ ............ ............ ............ ............ ...........E 3 3 10 ... .E. ... */二分匹配代码:
#include <set> #include <map> #include <cmath> #include <queue> #include <stack> #include <vector> #include <string> #include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> using namespace std; /* '0. Macros, Preprocessers, */ #pragma comment(linker, "/STACK:102400000,102400000") #ifdef _WIN32 typedef __int64 int64; #define OD(_TYPE) printf("%I64d\n", _TYPE) #define ODC(_CASE, _TYPE) printf("Case %d: %I64d\n", _CASE++, _TYPE); #else typedef long long int64; #define OD(_TYPE) printf("%lld\n", _TYPE) #define ODC(_CASE, _TYPE) printf("Case %d: %lld\n", _CASE++, _TYPE); #endif #define LSON l,mid,id<<1 #define RSON mid+1,r,id<<1|1 #define MM (l+r)>>1 /* '1. Constants, */ const double EPS = 1e-8; const double PI = acos(-1.0); const int INF = 0x3f3f3f3f; /* '2. Coding Area, */ const int N = 15; const int M = 205; const int dir[4][2] = { { -1, 0 }, { 0, 1 }, { 1, 0 }, { 0, -1 } }; struct STATE { int x, y, t; STATE() { } STATE(int x, int y, int t) : x(x), y(y), t(t) { } }; int uN, vN; vector<int> g[M]; int linker[M * M]; // 每一个v相应的u匹配 bool used[M * M]; char mp[N][N]; int dis[M][M]; // 每一个女孩到出口的最短时间 bool vis[N][N]; // 訪问过或没有 int r, c, T; int gid, eid; map<pair<int, int>, int> mpg, mpe; // 每一个点的编号 bool dfs(int u) { for (unsigned int i = 0; i < g[u].size(); i++) { int v = g[u][i]; if (used[v]) continue; used[v] = true; if (linker[v] == -1 || dfs(linker[v])) { linker[v] = u; return true; } } return false; } int hungary() { int res = 0; memset(linker, -1, sizeof(linker)); for (int u = 0; u < uN; u++) { memset(used, 0, sizeof(used)); if (dfs(u)) ++res; } return res; } void bfs(int x, int y) { queue<STATE> q; int eid = mpe[make_pair(x, y)]; memset(vis, 0, sizeof(vis)); vis[x][y] = 1; q.push(STATE(x, y, 0)); while (!q.empty()) { STATE now = q.front(); q.pop(); for (int i = 0; i < 4; i++) { int dx = now.x + dir[i][0]; int dy = now.y + dir[i][1]; if (dx >= 0 && dx < r && dy >= 0 && dy < c) { if (mp[dx][dy] != '.') continue; if (vis[dx][dy]) continue; int gid = mpg[make_pair(dx, dy)]; q.push(STATE(dx, dy, now.t + 1)); dis[gid][eid] = now.t + 1; vis[dx][dy] = 1; } } } } bool build_and_run(int limit) { for (int i = 0; i < M; i++) g[i].clear(); uN = gid, vN = eid * limit; for (int i = 0; i < gid; i++) { for (int j = 0; j < eid; j++) { for (int k = dis[i][j]; k <= limit; k++) { g[i].push_back(j * limit + k); } } } int ans = hungary(); if (ans >= gid) return true; return false; } void gao() { gid = eid = 0; mpg.clear(); mpe.clear(); memset(dis, 0x3f, sizeof(dis)); for (int i = 0; i < r; i++) { scanf("%s", mp[i]); for (int j = 0; j < c; j++) { if (mp[i][j] == 'E') mpe[make_pair(i, j)] = eid++; if (mp[i][j] == '.') mpg[make_pair(i, j)] = gid++; } } for (int i = 0; i < r; i++) { for (int j = 0; j < c; j++) { if (mp[i][j] == 'E') { bfs(i, j); } } } int L = 1, R = 256, ans = INF; while (L <= R) { int mid = (L + R) >> 1; if (build_and_run(mid)) { ans = mid; R = mid - 1; } else { L = mid + 1; } } if (ans == INF || ans > T) { printf("impossible\n"); } else { printf("%d\n", ans); } } int main() { while (~scanf("%d%d%d", &r, &c, &T)) { memset(g, 0, sizeof(g)); gao(); } return 0; }