[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;
} 

话说有没有人跟我一样,读完题面脑袋里就开始洗脑回放“狼爱上羊啊爱的疯狂……”啊雾~

posted @ 2021-01-16 16:33  Spring-Araki  阅读(67)  评论(0编辑  收藏  举报