BZOJ 1412 ZJOI 2009 狼和羊的故事 最小割

来源:互联网 发布:破解软件下载 编辑:程序博客网 时间:2024/05/18 01:56

题目大意:一个农场中有狼和羊,现在要将他们用围栏分开,问最少需要多少围栏。


思路:所有源向所有狼连边,所有羊向汇连边,图中的每个相邻的格子之间连边,然后跑S->T的最大流,也就是把狼和羊分开的最小割。


CODE:

#include <queue>#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#define MAX 11000#define MAXE 500010#define INF 0x3f3f3f3f#define S 0#define T (m * n + 1)using namespace std;const int dx[] = {0,1,-1,0,0};const int dy[] = {0,0,0,1,-1};int m,n;int src[110][110],num[110][110],cnt;int head[MAXE],total = 1;int next[MAXE],aim[MAXE],flow[MAXE];int deep[MAXE];inline void Add(int x,int y,int f){next[++total] = head[x];aim[total] = y;flow[total] = f;head[x] = total;}inline void Insert(int x,int y,int f){Add(x,y,f);Add(y,x,0);}inline bool BFS(){static queue<int> q;while(!q.empty())q.pop();memset(deep,0,sizeof(deep));deep[S] = 1;q.push(S);while(!q.empty()) {int x = q.front(); q.pop();for(int i = head[x]; i; i = next[i])if(!deep[aim[i]] && flow[i]) {deep[aim[i]] = deep[x] + 1;q.push(aim[i]);if(aim[i] == T)return true;}}return false;}int Dinic(int x,int f){if(x == T)return f;int temp = f;for(int i = head[x]; i; i = next[i])if(deep[aim[i]] == deep[x] + 1 && flow[i] && temp) {int away = Dinic(aim[i],min(flow[i],temp));if(!away)deep[aim[i]] = 0;flow[i] -= away;flow[i^1] += away;temp -= away;}return f - temp;}int main(){cin >> m >> n;for(int i = 1; i <= m; ++i)for(int j = 1; j <= n; ++j) {scanf("%d",&src[i][j]),num[i][j] = ++cnt;if(src[i][j] == 1)Insert(S,num[i][j],INF);if(src[i][j] == 2)Insert(num[i][j],T,INF);}for(int i = 1; i <= m; ++i)for(int j = 1; j <= n; ++j)for(int k = 1; k <= 4; ++k) {int fx = i + dx[k];int fy = j + dy[k];if(!num[fx][fy])continue;Insert(num[i][j],num[fx][fy],1);}int max_flow = 0;while(BFS())max_flow += Dinic(S,INF);cout << max_flow << endl;return 0;}


1 0