Luogu – P2598 – [ZJOI2009]狼和羊的故事

题意

给定一个 $n\times m$ 的矩阵,矩阵上每一个点可能是狼、羊或者空地。

你需要在格子的边界修建篱笆,使得任意两个狼与羊的格子不连通。

给一个格子的一条边界修建篱笆,那么篱笆总长度增加 $1$,求篱笆的最短长度。

$n, m\leq 100$.

分析

这是最小割问题的常见模型。

网络流可以用于解决矩阵上,通过限制边,与连通性相关的问题。

这道题,需要把狼和羊分开,所以想到:

源点向所有狼连容量为 $\inf$ 的边;

所有羊向汇点连容量为 $\inf$ 的边;

这样使狼和羊一定分别属于两个集合。

之后对矩阵上的限制进行模拟,所有点向四周连容量为 $1$ 的边。

这样断掉一条边,就等价于在矩阵中选一条边界拦住。

代码

#include <bits/stdc++.h>

using namespace std;
const int MAXN = 10008, MAXM = 1e7;
const int inf = 0x3f3f3f3f;
int n, m, S, T;
int dir[4][2] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
int num[MAXN][MAXN];
int get_id(int x, int y) {
	return (x - 1) * m + y;
}
struct Edge{
	int to, val, nxt;
} edge[MAXM];
int head[MAXN], e_cnt = 1;
void add(int u, int v, int w) {
	edge[++e_cnt] = (Edge){v, w, head[u]};
	head[u] = e_cnt;
}
void add_edge(int u, int v, int w) {
	add(u, v, w); add(v, u, 0);
}
int lev[MAXN];
bool bfs() {
	memset(lev, -1, sizeof(lev)); lev[S] = 0;
	queue<int> q; q.push(S);
	while(!q.empty()) {
		int u = q.front(); q.pop();
		for(int i = head[u]; i; i = edge[i].nxt) {
			int v = edge[i].to, val = edge[i].val;
			if(lev[v] == -1 && val) {
				lev[v] = lev[u] + 1;
				q.push(v);
			}
		}
	}
	return (lev[T] != -1);
}
int dfs(int u, int flow) {
	if(u == T) return flow;
	int ret = 0;
	for(int i = head[u]; i; i = edge[i].nxt) {
		int v = edge[i].to, val = edge[i].val;
		if(lev[v] == lev[u] + 1 && val) {
			int tmp = dfs(v, min(flow, val));
			edge[i].val -= tmp;
			edge[i ^ 1].val += tmp;
			flow -= tmp;
			ret += tmp;
			if(flow == 0) break;
		}
	}
	if(ret == 0) lev[u] = -1;
	return ret;
}
int Dinic() {
	int ret = 0;
	while(bfs()) {
		ret += dfs(S, inf);
	}
	return ret;
}
int main() {
	scanf("%d%d", &n, &m);
	S = 0; T = n * m + 1;
	for(int i = 1; i <= n; i++) {
		for(int j = 1; j <= m; j++) {
			scanf("%d", &num[i][j]);
			int id = get_id(i, j);
			if(num[i][j] == 1) add_edge(S, id, inf);
			if(num[i][j] == 2) add_edge(id, T, inf);
			for(int k = 0; k < 4; k++) {
				int nx = i + dir[k][0], ny = j + dir[k][1];
				if(nx < 1 || ny < 1 || nx > n || ny > m) continue;
				add_edge(id, get_id(nx, ny), 1);
			}
		}
	}
	cout << Dinic() << endl;
	return 0;
}
暂无评论

发送评论 编辑评论

|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇