题目:
“狼爱上羊啊爱的疯狂,谁让他们真爱了一场;狼爱上羊啊并不荒唐,他们说有爱就有方向......” Orez听到这首歌,心想:狼和羊如此和谐,为什么不尝试羊狼合养呢?说干就干! Orez的羊狼圈可以看作一个n*m个矩阵格子,这个矩阵的边缘已经装上了篱笆。可是Drake很快发现狼再怎么也是狼,它们总是对羊垂涎三尺,那首歌只不过是一个动人的传说而已。所以Orez决定在羊狼圈中再加入一些篱笆,还是要将羊狼分开来养。 通过仔细观察,Orez发现狼和羊都有属于自己领地,若狼和羊们不能呆在自己的领地,那它们就会变得非常暴躁,不利于他们的成长。 Orez想要添加篱笆的尽可能的短。当然这个篱笆首先得保证不能改变狼羊的所属领地,再就是篱笆必须修筑完整,也就是说必须修建在单位格子的边界上并且不能只修建一部分。
文件的第一行包含两个整数n和m。接下来n行每行m个整数,1表示该格子属于狼的领地,2表示属于羊的领地,0表示该格子不是任何一只动物的领地。
思路:
一开始没往网络流想,想了一些乱七八糟的找规律方法,无果。看了标签才想到做法......
将每个格子当做一个点,源点S向所有1连边,所有2向汇点T连边,其边权均为INF;然后0或1向相邻的0或2的点连边,其边权均为1;这样问题转化为使源点不能到达汇点的最小割。权当复习一遍Dinic吧。。。
代码:
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <queue>
#include <vector>
#include <cstring>
#define For(i,j,k) for(int i = j;i <= (int)k;i++)
#define Forr(i,j,k) for(int i = j;i >= (int)k;i--)
#define Set(i,j) memset(i, j, sizeof(i))
#define pb push_back
using namespace std;
const int N = 110, M = N * N;
const int d[4][2] = {0, 1, 0, -1, 1, 0, -1, 0};
int n, m, cnt = 1, Map[N][N], id[N][N];
struct Edge{
int to, flow, cap;
};
struct Dinic{
vector<int> G[M];
int S, T, e;
int dis[M], cur[M];
bool vis[M];
Edge E[M<<4];
void Add(int x, int y, int f){
E[e] = (Edge){y, 0, f}, G[x].pb(e++);
E[e] = (Edge){x, 0, 0}, G[y].pb(e++);
}
bool BFS(){
Set(vis, 0);
queue<int> q;
q.push(S);
vis[S] = 1, dis[S] = 0;
while(!q.empty()){
int h = q.front(); q.pop();
For(i,0,G[h].size() - 1){
Edge& s = E[G[h][i]];
if(vis[s.to] || s.flow == s.cap) continue;
vis[s.to] = 1, dis[s.to] = dis[h] + 1;
q.push(s.to);
}
}
return vis[T];
}
int DFS(int h, int f){
if(h == T) return f;
int sum = 0;
for(int &i = cur[h];i < G[h].size() && sum < f;i++){
Edge& s = E[G[h][i]];
int t;
if(dis[h] + 1 == dis[s.to] && (t = DFS(s.to, min(s.cap - s.flow, f - sum)))){
sum += t;
s.flow += t;
E[G[h][i] ^ 1].flow -= t;
}
}
return sum;
}
int Maxflow(int s, int t){
S = s, T = t;
int Ans = 0;
while(BFS()){
Set(cur, 0);
Ans += DFS(S, 1e9);
}
return Ans;
}
}S;
int main(){
scanf("%d%d", &n, &m);
For(i,1,n) For(j,1,m) scanf("%d", &Map[i][j]), id[i][j] = ++cnt;
For(i,1,n) For(j,1,m){
if(Map[i][j] == 1) S.Add(0, id[i][j], 1e9);
else if(Map[i][j] == 2){
S.Add(id[i][j], 1, 1e9);
continue;
}
For(v,0,3){
int x = i + d[v][0], y = j + d[v][1];
if(Map[x][y] != 1) S.Add(id[i][j], id[x][y], 1);
}
}
printf("%d\n", S.Maxflow(0, 1));
return 0;
}