[ZJOI2009] 狼和羊的故事
怎么说呢,这道题其实不难,只是题意有那么亿点点难理解。我最开始想复杂了,理解为了栅栏长度是格点的周长,那事情就复杂了。。。
题目分析:
- 首先,要明确的是:一个狼领地和羊领地之间只需建长度为 \(1\) 的栅栏。确定源点为狼,汇点为羊,正常连边,注意边权为极大值,因为不确定一只狼会和几只羊相邻,所以直接来极大值;
因为要狼和羊之间不影响,意思就是说要源点和汇点之间不联通,就是明显的最小割啦。
-
然后,连相邻个点之间的边,如果该格点是羊,不会造成任何影响
卑微,要考虑的是空地和狼的情况。如果两块都是狼,也不会产生影响(羊都没有吃个寂寞)。那么剩下的情况直接连边,边权为\(1\),即修一次栅栏; -
最后,最小割模板求出答案就好啦。
完整代码:
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define rt register int
const int N = 1e4 + 10,M = 1e5 + 10,inf = 1e9;
struct node {
int to,nex;
}e[M];
int n,m,s,t,top,ed,map[105][105],dep[N],head[N],cur[N],tot = 1,f[M],q[N],a[4][2] = {{0,1},{1,0},{-1,0},{0,-1}};
inline void add(int x,int y,int w) {
e[++tot] = (node) {y,head[x]}, f[tot] = w, head[x] = tot;
e[++tot] = (node) {x,head[y]}, head[y] = tot;
}
inline bool bfs() {
memset(dep,-1,sizeof(dep));
dep[s] = 0, cur[s] = head[s], q[top = 1] = s; ed = 1;
int now,ver;
while(top <= ed) {
now = q[top++];
for(rt i = head[now]; i; i = e[i].nex) {
ver = e[i].to;
if(dep[ver] == -1 && f[i]) {
dep[ver] = dep[now] + 1, cur[ver] = head[ver];
if(ver == t) return 1;
q[++ed] = ver;
}
}
}
return 0;
}
inline int find(int x,int limit) {
if(x == t) return limit;
int flow = 0, tmp, ver;
for(rt i = head[x]; i && flow < limit; i = e[i].nex) {
ver = e[i].to;
if(dep[ver] == dep[x] + 1 && f[i]) {
tmp = find(ver,min(limit - flow,f[i]));
if(!tmp) dep[ver] = -1;
f[i] -= tmp, f[i ^ 1] += tmp, flow += tmp;
}
}
return flow;
}
inline int dinic() {
int res = 0, flow;
while(bfs()) res += find(s,inf);
return res;
}
inline void read(int &x) {
x = 0;int ff = 1;
char s = getchar();
while(s < '0' || s > '9') {if(s == '-') ff = -1;s = getchar();}
while(s <= '9' && s >= '0') {x = x * 10 + s - '0', s = getchar(); }
x *= ff;
}
inline int pos(int x,int y) {
return m * (x - 1) + y;
}
int main() {
read(n), read(m);
s = n * m + 1, t = s + 1;
for(rt i = 1; i <= n; i ++) {
for(rt j = 1; j <= m; j ++) {
read(map[i][j]);
if(map[i][j] == 1) add(s,pos(i,j),inf);//狼
if(map[i][j] == 2) add(pos(i,j),t,inf);//羊
}
}
int tx,ty;
for(rt i = 1; i <= n; i ++) {
for(rt j = 1; j <= m; j ++) {
for(rt k = 0; k < 4; k ++) {//上下左右
tx = i + a[k][0], ty = j + a[k][1];
if(tx < 1 || ty < 1 || tx > n || ty > m || map[i][j] == 2) continue;//排除越界和羊的情况
if(map[i][j] != 1 || map[tx][ty] != 1) add(pos(i,j),pos(tx,ty),1);//排除两只都是狼的情况
}
}
}
printf("%d",dinic());
return 0;
}
话说有没有人跟我一样,读完题面脑袋里就开始洗脑回放“狼爱上羊啊爱的疯狂……”啊雾~