P3191 EVACUATE
Lunacturne_ · · 题解
不错的网络流题。
首先二分答案
可以考虑把每一个门都拆开成
建图方式如下:
- 源点
S 连向每一个人。 - 每个门拆改每个时间的点连向汇点。
预处理出每个人到门的距离,连到这个时间的门。
有一个问题就是可能好多人同时到达同一扇门。
可以把一扇门
因为
// Author: Jerry_Jiang
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define ull unsigned long long
#define ALL(a) (a).begin(), (a).end()
#define pb push_back
#define mk make_pair
#define pii pair<int, int>
#define pis pair<int, string>
#define sec second
#define fir first
#define sz(a) int((a).size())
#define Yes cout << "Yes" << endl
#define YES cout << "YES" << endl
#define No cout << "No" << endl
#define NO cout << "NO" << endl
#define debug(x) cerr << #x << ": " << x << endl
#define double long double
#define mms(arr, n) memset(arr, n, sizeof(arr))
#define rep(i, a, n) for (int i = (a); i <= (n); ++i)
#define per(i, n, a) for (int i = (n); i >= (a); --i)
int max(int a, int b)
{
if (a > b)
return a;
return b;
}
int min(int a, int b)
{
if (a < b)
return a;
return b;
}
const int INF = 0x3f3f3f3f3f3f3f3f;
const int MOD = 1000000007;
const int N = 2e5 + 10, M = 1e6 + 10;
const int dx[4] = {-1, 1, 0, 0};
const int dy[4] = {0, 0, -1, 1};
namespace MaxFlow
{
// Here, M needs to be doubled.
// In this program, int <-> long long
int head[N], nxt[M], to[M], cnt = 1;
int lim[M];
void init()
{
memset(head, 0, sizeof(head));
cnt = 1;
}
void addEdge(int u, int v, int w)
{
// cerr << u << " " << v << " " << w << endl;
nxt[++cnt] = head[u], head[u] = cnt, to[cnt] = v, lim[cnt] = w;
nxt[++cnt] = head[v], head[v] = cnt, to[cnt] = u, lim[cnt] = 0;
}
int T, dis[N], cur[N];
int dfs(int u, int res)
{
if (u == T)
return res;
int flow = 0;
for (int i = cur[u]; i && res; i = nxt[i])
{
cur[u] = i;
int v = to[i];
int c = min(res, lim[i]);
if (c && dis[v] == dis[u] + 1)
{
int k = dfs(v, c);
flow += k;
res -= k;
lim[i] -= k;
lim[i ^ 1] += k;
}
}
if (!flow)
dis[u] = -1;
return flow;
}
int maxflow(int s, int t)
{
T = t;
int flow = 0;
while (1)
{
queue<int> q;
memset(dis, -1, sizeof(dis));
memcpy(cur, head, sizeof(head));
dis[s] = 0;
q.push(s);
while (!q.empty())
{
int u = q.front();
q.pop();
for (int i = head[u]; i; i = nxt[i])
{
int v = to[i];
if (dis[v] == -1 && lim[i])
{
dis[v] = dis[u] + 1;
q.push(v);
}
}
}
if (dis[t] == -1)
return flow;
flow += dfs(s, INF);
}
}
};
// bool st;
int n, m, dis[410][22][22], cnt = 0;
char s[22][22];
int id[22][22];
queue<pii> q;
// bool en;
void BFS(int sx, int sy)
{
q.push({sx, sy});
dis[id[sx][sy]][sx][sy] = 0;
while (!q.empty())
{
int x = q.front().first, y = q.front().second;
q.pop();
for (int i = 0; i < 4; i++)
{
int tx = x + dx[i], ty = y + dy[i];
if (tx >= 1 && tx <= n && ty >= 1 && ty <= m && s[tx][ty] != 'X' && dis[id[sx][sy]][tx][ty] > 1e9)
{
dis[id[sx][sy]][tx][ty] = dis[id[sx][sy]][x][y] + 1;
q.push({tx, ty});
}
}
}
}
bool check(int L)
{
int S = 0, T = 2e5;
MaxFlow::init();
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
{
if (s[i][j] == '.')
{
MaxFlow::addEdge(S, id[i][j], 1);
for (int x = 1; x <= n; x++)
for (int y = 1; y <= m; y++)
if (s[x][y] == 'D' && dis[id[i][j]][x][y] <= L)
{
MaxFlow::addEdge(id[i][j], id[x][y] + (dis[id[i][j]][x][y] - 1) * 400, 1);
}
}
else if (s[i][j] == 'D')
{
for (int k = 1; k <= L; k++)
{
MaxFlow::addEdge(id[i][j] + (k - 1) * 400, T, 1);
if (k < L)
MaxFlow::addEdge(id[i][j] + (k - 1) * 400, id[i][j] + k * 400, INF);
}
}
}
return MaxFlow::maxflow(S, T) == cnt;
}
void solve()
{
scanf("%lld%lld", &n, &m);
for (int i = 1; i <= n; i++)
scanf("%s", s[i] + 1);
memset(dis, 0x3f, sizeof(dis));
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
{
id[i][j] = (i - 1) * m + j;
if (s[i][j] == '.')
{
cnt++;
BFS(i, j);
}
}
int l = 0, r = 400;
while (l < r)
{
int mid = (l + r) >> 1;
if (check(mid))
r = mid;
else
l = mid + 1;
}
if (!check(l))
puts("impossible");
else
printf("%lld\n", l);
}
signed main()
{
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
// cerr<<(&en-&st)/1024.0/1024.0<<endl;
// ios::sync_with_stdio(false);
// cin.tie(0);
// cout.tie(0);
int testcase = 1;
// cin >> testcase;
while (testcase--)
solve();
return 0;
}