1. 程式人生 > 其它 >[ZJOI2009]狼和羊的故事 題解

[ZJOI2009]狼和羊的故事 題解

技術標籤:題解演算法網路圖c++

狼和羊的故事

怎麼說呢,這道題其實不難,只是題意有那麼點點難理解。我最開始想複雜了,理解為了柵欄長度是格點的周長,那事情就複雜了。。。

題目分析

  • 首先,要明確的是:一個狼領地和羊領地之間只需建長度為 1 1 1 的柵欄。確定源點為狼,匯點為羊,正常連邊,注意邊權為極大值,因為不確定一隻狼會和幾隻羊相鄰,所以直接來極大值;

因為要狼和羊之間不影響,意思就是說要源點和匯點之間不聯通,就是明顯的最小割啦。

  • 然後,連相鄰個點之間的邊,如果該格點是羊,不會造成任何影響卑微,要考慮的是空地和狼的情況。如果兩塊都是狼,也不會產生影響(羊都沒有吃個寂寞)。那麼剩下的情況直接連邊,邊權為 1 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; }

話說有沒有人跟我一樣,讀完題面腦袋裡就開始洗腦回放“狼愛上羊啊愛的瘋狂……”啊霧~