题解 AT2568 【Lotus Leaves】
Daniel_yuan · · 题解
题目要求最少需要将多少个 o 改成 . ,可以使这个人无法从 S 到达 T 。很容易想到最小割。
由最小割等于最大流可以想到一个特别 naive 的想法:S 只连出边,T 只连入边,其它点向其能到达的点连边,然后跑网络流。
因为点与点之间连的边只是为了连通两个点,所以边权是
对于这种限制点权的网络流,一种简单的方法是把一个点拆成一个入点和一个出点,并且在入点和出点之间连一条流量为点权的边。所有以该点为终点的边全部连到它的入点,反之则连到它的出点。
这样连好后就可以跑网络流了,但是对于每个点,其在每一行内最多有
不难发现,对于同一行或者同一列的点,都是互相可达,那么其实不需要两两连边,只需要对于每行和列建一个辅助节点作为中转,即可把边数降到
最后的最大流就是所求答案,至于判断可行性,可以一开始就看 S 和 T 在不在同一行或同一列内,也可以看跑完网络流后是不是割了
代码如下:
#include <bits/stdc++.h>
#define RI register int
typedef long long LL;
#define FILEIO(name) freopen(name".in", "r", stdin), freopen(name".out", "w", stdout);
using namespace std;
char buf[1000000], *p1 = buf, *p2 = buf;
inline char gc() {
if (p1 == p2) p2 = (p1 = buf) + fread(buf, 1, 1000000, stdin);
return p1 == p2 ? EOF : *(p1++);
}
template <class T> inline void read(T &n) {
n = 0; RI ch = gc(), f;
while ((ch < '0' || ch > '9') && ch != '-') ch = gc();
f = (ch == '-' ? ch = gc(), -1 : 1);
while (ch >= '0' && ch <= '9') n = n * 10 + (ch ^ 48), ch = gc();
n *= f;
}
int const MAXN = 105, INF = 0x7f7f7f7f;
struct Edges { int to, next, dis; } e[MAXN * MAXN * MAXN];
int head[MAXN * MAXN * MAXN], tot = 1;
int In[MAXN][MAXN], Out[MAXN][MAXN], cnt, S, T, Row[MAXN], Line[MAXN];
int dep[MAXN * MAXN * MAXN], cur[MAXN * MAXN * MAXN];
char s[MAXN][MAXN];
queue <int> q;
inline void addedge(int from, int to, int dis) {
e[++tot] = (Edges){to, head[from], dis};
head[from] = tot;
e[++tot] = (Edges){from, head[to], 0};
head[to] = tot;
}
bool Bfs() {
memset(dep, 0, sizeof(dep));
dep[S] = 1;
q.push(S);
while (!q.empty()) {
int t = q.front(); q.pop();
for (RI i = head[t]; i; i = e[i].next)
if (!dep[e[i].to] && e[i].dis)
dep[e[i].to] = dep[t] + 1, q.push(e[i].to);
}
if (!dep[T]) return 0;
for (RI i = 1; i <= cnt; ++i) cur[i] = head[i];
return 1;
}
int Dfs(int now, int res) {
if (now == T || !res) return res;
int sum = 0;
for (RI i = cur[now]; i; i = e[i].next) {
cur[now] = i;
if (dep[e[i].to] == dep[now] + 1) {
int d = Dfs(e[i].to, min(res, e[i].dis));
if (d) {
sum += d;
res -= d;
e[i].dis -= d;
e[i ^ 1].dis += d;
}
}
}
return sum;
}
int Dinic() {
int Maxflow = 0;
while (Bfs())
Maxflow += Dfs(S, INF);
return Maxflow;
}
int main() {
#ifdef LOCAL
FILEIO("a");
#endif
int n, m; scanf("%d %d", &n, &m);
for (RI i = 1; i <= n; ++i)
scanf("%s", s[i] + 1);
for (RI i = 1; i <= n; ++i) Row[i] = ++cnt;
for (RI i = 1; i <= m; ++i) Line[i] = ++cnt;
for (RI i = 1; i <= n; ++i)
for (RI j = 1; j <= m; ++j) {
if (s[i][j] == 'o') {
In[i][j] = ++cnt, Out[i][j] = ++cnt;
addedge(Out[i][j], Row[i], INF);
addedge(Out[i][j], Line[j], INF);
addedge(Row[i], In[i][j], INF);
addedge(Line[j], In[i][j], INF);
addedge(In[i][j], Out[i][j], 1);
}
if (s[i][j] == 'S') {
S = ++cnt;
addedge(S, Row[i], INF);
addedge(S, Line[j], INF);
}
if (s[i][j] == 'T') {
T = ++cnt;
addedge(Row[i], T, INF);
addedge(Line[j], T, INF);
}
}
int Maxflow = Dinic();
if (Maxflow > n * m) puts("-1");
else printf("%d\n", Maxflow);
return 0;
}
// created by Daniel yuan