(毛绒绒的题)忽然就想起beastars。
题目 ------Link------
题目
解
最小割=网络流中的最大流。
建图:
S -> 羊:边权 = INF
羊->空地,羊->狼,空地->狼:边权 = 1
狼->T:边权 = INF
然后网络流跑个最大流即可。
代码
#include<cstdio>
#include<iostream>
#include<queue>
#include<cmath>
#include<cstring>
#define innf 1000000000
using namespace std;
int n,m,s,t,tot,lx[101][101],B[100001],dis[100001],l[100001];
int fx[6] = {0,0,+1,-1}, fy[6] = {+1,-1,0,0};
struct asdf{
int to, next, sy, ff;
} a[10000001];
void add(int xx, int yy, int zz){ //建边
a[++tot] = (asdf){yy, l[xx], zz, tot + 1}; l[xx] = tot;
a[++tot] = (asdf){xx, l[yy], 0, tot - 1}; l[yy] = tot;
}
bool spfa(){ //寻找增广路
queue<int> Q;
memset(B, 0, sizeof(B));
memset(dis, 0x7f, sizeof(dis));
dis[s] = 0; B[s] = 1;
Q.push(s);
while(Q.size()){
int h = Q.front();
Q.pop();
B[h] = 0;
for(int i = l[h]; i; i = a[i].next)
if(a[i].sy && dis[h] + 1 < dis[a[i].to]){
dis[a[i].to] = dis[h] + 1;
if(a[i].to == t) return 1;
if(B[a[i].to] == 0){
B[a[i].to] = 1;
Q.push(a[i].to);
}
}
}
return 0;
}
int dfs(int d, int minn){ //增广
if(d == t) return minn;
int ljl = 0;
for(int i = l[d]; i; i = a[i].next)
if(a[i].sy && dis[d] + 1 == dis[a[i].to]){
int ll = dfs(a[i].to, min(minn - ljl, a[i].sy));
a[i].sy -= ll;
a[a[i].ff].sy += ll;
ljl += ll;
if(ljl == minn) return ljl;
}
return ljl;
}
int dinic(){ //网络流
int ans = 0;
while(spfa()) ans += dfs(s, innf);
return ans;
}
int main(){
scanf("%d%d", &n, &m);
s = 0; t = n * m + 1;
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= m; ++j){ //与s,t建边
scanf("%d", &lx[i][j]);
if(lx[i][j] == 1) add(s, (i - 1) * m + j, innf);
if(lx[i][j] == 2) add((i - 1) * m + j, t, innf);
}
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= m; ++j)
if(lx[i][j] < 2){
int bh1 = (i - 1) * m + j;
for(int k = 0; k < 4; ++k){ //向四周连边
int xx = i + fx[k], yy = j + fy[k], bh2 = (xx - 1) * m + yy;
if(xx < 1 || xx > n || yy < 1 || yy > m) continue;
if(lx[i][j] == 0 && lx[xx][yy] != 1) add(bh1, bh2, 1);
if(lx[i][j] == 1 && lx[xx][yy] != 1) add(bh1, bh2, 1);
}
}
printf("%d", dinic());
}