题目链接:点击跳转
可以用网络流解决,难点在于如何建图。
针对每一个点,他们都可以移动到四周的点上,那么对于每个点,向四周的点建一条流量为1的边,对于每一个1的点,建一条源点到这个点的边,流量为inf,对于每一个2的点,建一条这个点到汇点的边,流量为inf。这样子,这个问题就被转化为最大流问题,因为最大流=最小割,那么最后得到的就是题目要求的答案。
代码如下:
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ll;
const int MAXN = 5e5 + 5e2;
const int INF = 0x3f3f3f3f;
#define endl '\n'
inline void IO_STREAM() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
}
struct Edge{
int to,val,nxt;
}e[MAXN];
int head[MAXN], deep[MAXN], gra[205][205], to[4][2] = {1, 0, -1, 0, 0, 1, 0, -1};
int n, m, s, t, cnt;
ll res;
inline void init() {
memset(head, -1, sizeof(head));
cnt = 0;
res = 0;
}
inline void add(int from, int to, int val) {
e[cnt] = Edge{to, val, head[from]};
head[from] = cnt++;
}
inline bool check(int x, int y) {
if (x >= 0 && x < n && y >= 0 && y < m) return true;
return false;
}
inline void addPath(int x, int y) {
for (int i = 0; i < 4; i++) {
int xx = x + to[i][0];
int yy = y + to[i][1];
if (check(xx, yy)) {
add(xx * m + yy + 1, x * m + y + 1, 1);
add(x * m + y + 1, xx * m + yy + 1, 0);
}
}
if (gra[x][y] == 1) {
add(x * m + y + 1, t, INF);
add(t, x * m + y + 1, 0);
} else if (gra[x][y] == 2){
add(s, x * m + y + 1, INF);
add(x * m + y + 1, s, 0);
}
}
inline bool bfs() {
memset(deep, -1, sizeof(deep));
deep[s] = 1;
queue<int>q;
q.push(s);
while (!q.empty()) {
int front = q.front();
q.pop();
for (int i = head[front]; i != -1; i = e[i].nxt) {
if (deep[e[i].to] == -1 && e[i].val) {
deep[e[i].to] = deep[front] + 1;
q.push(e[i].to);
}
}
}
return (deep[t] != -1);
}
inline int dfs(int x, int totFlow) {
if (x == t || totFlow ==0) return totFlow;
int ans = totFlow;
for (int i = head[x]; i != -1; i = e[i].nxt) {
if (deep[e[i].to] == deep[x] + 1 && e[i].val) {
int flow = dfs(e[i].to, min(totFlow, e[i].val));
e[i].val -= flow;
e[i ^ 1].val += flow;
totFlow -= flow;
if (totFlow == 0) return ans;
}
}
return ans - totFlow;
}
inline void dinic() {
while (bfs()) {
res += dfs(s, INF);
}
}
int main() {
IO_STREAM();
int Case = 1;
while (cin >> n >> m) {
init();
s = 0, t = n * m + 5;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
cin >> gra[i][j];
}
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
addPath(i, j);
}
}
dinic();
cout << "Case " << Case++ << ":" << endl;
cout << res << endl;
// cout.flush(); //debug
}
return 0;
}