Description
Solution
看上去很像网络流但是还是不会做啊!!!
正解要二分答案然后网络流判定能否走出去,因为一个时刻只能出去一个人,所以门是有流量限制的,这样看是否满流就行了。
然后建图要注意只有能到的点才向门连边,不要“穿墙”。
UPD:BZOJ的数据好像卡了这种建图方法……所以要把门拆成时刻建图,麻烦的要死……就没有写……
Code
const int N = 410;
const int M = 20 * N * N * 2;
const int INF = 0x3f3f3f3f;
int hd[N], to[M], nxt[M], cap[M], cnt;
int d[N], qhd, qtl, q[N], s, t;
int n, m, id[N][N];
char mp[40][40];
void init() {
cnt = 1;
memset(hd, 0, sizeof hd);
memset(nxt, 0, sizeof nxt);
}
void Adde(int x, int y, int z) {
to[++cnt] = y;
cap[cnt] = z;
nxt[cnt] = hd[x];
hd[x] = cnt;
}
void adde(int x, int y, int z) {
Adde(x, y, z);
Adde(y, x, 0);
}
bool bfs() {
memset(d, 0, sizeof d);
qhd = qtl = 0;
d[q[qtl++] = s] = 1;
while (qhd != qtl) {
int x = q[qhd++];
for (int i = hd[x]; i; i = nxt[i]) {
if (cap[i] && !d[to[i]]) d[q[qtl++] = to[i]] = d[x] + 1;
}
if (d[t]) break;
}
return d[t];
}
int dfs(int x, int flw) {
if (x == t || !flw) return flw;
int ret = 0;
for (int i = hd[x]; i; i = nxt[i])
if (cap[i] && d[to[i]] == d[x] + 1) {
int tmp = dfs(to[i], std::min(flw, cap[i]));
if (tmp > 0) {
ret += tmp;
flw -= tmp;
cap[i ^ 1] += tmp;
cap[i] -= tmp;
}
}
return ret;
}
int dinic() {
int flw = 0;
while (bfs()) {
flw += dfs(s, INF);
}
return flw;
}
int vis[N][N];
void adde(int x, int y, int tx, int ty, int mxd) {
if (abs(tx - x) + abs(ty - y) > mxd || vis[x][y]) return;
vis[x][y] = 1;
if (mp[x][y] == '.') adde(id[x][y], id[tx][ty], 1);
if (mp[x - 1][y] == '.') adde(x - 1, y, tx, ty, mxd);
if (mp[x + 1][y] == '.') adde(x + 1, y, tx, ty, mxd);
if (mp[x][y - 1] == '.') adde(x, y - 1, tx, ty, mxd);
if (mp[x][y + 1] == '.') adde(x, y + 1, tx, ty, mxd);
}
bool check(int x) {
init();
int tot = 0;
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= m; ++j) {
if (mp[i][j] == '.') {
adde(s, id[i][j], 1);
tot++;
} else if (mp[i][j] == 'D') {
adde(id[i][j], t, x);
memset(vis, 0, sizeof vis);
adde(i, j, i, j, x);
}
}
}
return dinic() == tot;
}
void main() {
n = read(), m = read();
s = 0, t = n * m + 1;
for (int i = 1; i <= n; ++i) scanf("%s", mp[i] + 1);
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j) id[i][j] = j + (i - 1) * m;
int l = 0, r = n * m * n * m + 1, ans = -1;
while (l <= r) {
int mid = (l + r) >> 1;
if (check(mid)) {
r = mid - 1;
ans = mid;
} else {
l = mid + 1;
}
}
if (~ans)
printf("%d
", ans);
else
puts("impossible");
}
Note
每次网络流的题都要调好久啊,这样下去不就gg了吗……