有一个
n
∗
m
n*m
n∗m的格子, 一个人起点
(
1
,
1
)
(1,1)
(1,1), 目的点是
(
n
,
m
)
(n,m)
(n,m)可以往右/往下走, #为不能走的点, 问做少把几个.改成#(不能改起点和终点)能让这个人不能走到.
当然最多改2个鸭
最小割就是最大流啊
网络流冲冲冲
把图里的每个格子拆成两个点, 其间的流量就是去掉这个点的代价(1), 当然第一个点和最后一个点代价是inf.
然后每个点的2号向其下/右的点的1号连边, 流量是inf.
然后从起点到终点跑网络流就行了.
注意这样n*m的图, 拆点可以学习ZGQ的函数:
int point1(int i, int j) {
return i * mm + j;
}
int point2(int i, int j) {
return i * mm + j + nn * mm;
}
真的强啊
注意自己的板子要初始化n.(当然不是图上的n啊!!)
代码:
#include<bits/stdc++.h>
#define FAST ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0)
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int maxN = 2200050;
const int maxM = 4200050;
namespace DINIC {
int n;// 这个n要记得初始化
int cnt;
int Head[maxN];
int Next[maxM << 1];
int W[maxM << 1];
int V[maxM << 1];
int Depth[maxN];
int cur[maxN];//cur就是记录当前点u循环到了哪一条边
int s, t;
void init2() {// 初始化函数记得调用
cnt = -1;
memset(Head, -1, sizeof(int) * n);
memset(Next, -1, sizeof(int) * n);
}
void _Add(int u, int v, ll w) {// 不要用
cnt++;
Next[cnt] = Head[u];
Head[u] = cnt;
V[cnt] = v;
W[cnt] = w;
}
void Add_Edge(int u, int v, int w) {// 用这个
_Add(u, v, w);
_Add(v, u, 0);
}
int dfs(int u, int flow) {
if (u == t)
return flow;
for (int &i = cur[u]; i != -1; i = Next[i]) {
//注意这里的&符号,这样i增加的同时也能改变cur[u]的值,达到记录当前弧的目的
if ((Depth[V[i]] == Depth[u] + 1) && (W[i] != 0)) {
int di = dfs(V[i], min(flow, W[i]));
if (di > 0) {
W[i] -= di;
W[i ^ 1] += di;
return di;
}
}
}
return 0;
}
int bfs() {
queue<int> Q;
while (!Q.empty())
Q.pop();
memset(Depth, 0, sizeof(Depth));
Depth[s] = 1;
Q.push(s);
do {
int u = Q.front();
Q.pop();
for (int i = Head[u]; i != -1; i = Next[i]) {
if ((Depth[V[i]] == 0) && (W[i] > 0)) {
Depth[V[i]] = Depth[u] + 1;
Q.push(V[i]);
}
}
} while (!Q.empty());
if (Depth[t] > 0)
return 1;
return 0;
}
int Dinic() {
int Ans = 0;
while (bfs()) {
for (int i = 1; i <= n; i++)
cur[i] = Head[i];
while (ll d = dfs(s, inf)) {
Ans += d;
}
}
return Ans;
}
};
string mp[1123456];
int nn, mm;
int point1(int i, int j) {
return i * mm + j;
}
int point2(int i, int j) {
return i * mm + j + nn * mm;
}
void init() {
using namespace DINIC;
FAST;
cin >> nn >> mm;
for (int i = 0; i < nn; ++i) {
cin >> mp[i];
}
n = point2(nn - 1, mm - 1) + 100;
init2();
for (int i = 0; i < nn; ++i) {
for (int j = 0; j < mm; ++j) {
if (mp[i][j] == '#')continue;
if ((i == 0 && j == 0) || (i == nn - 1 && j == mm - 1))
Add_Edge(point1(i, j), point2(i, j), inf);
else
Add_Edge(point1(i, j), point2(i, j), 1);
if (i + 1 < nn && mp[i + 1][j] != '#')
Add_Edge(point2(i, j), point1(i + 1, j), inf);
if (j + 1 < mm && mp[i][j + 1] != '#')
Add_Edge(point2(i, j), point1(i, j + 1), inf);
}
}
s = point1(0, 0), t = point2(nn - 1, mm - 1);
int ans = Dinic();
cout << ans << endl;
}
int main() {
init();
return 0;
}