[刷题记录] 网络流建模

前言

以后应该是\(1\)\(3\)道网络流的题目 总结如何建模

\(\text {Day1}\)

ZJOI 狼和羊的故事

题面

有一个网格图,网格上有数字,0表示无东西,1表示有羊,2表示有狼,你需要给网格修建篱笆以划分界限,使狼与羊分隔开,求篱笆的最短长。

建模

思路

这道题显然是让我们求最小割,又根据最大流最小割定理,我们只要求整张图的最大流就行了。
我们将每只羊与源点连接,每只狼与汇点连接,流量为\(INF\)
网格图我们可以将每个网格转化为一个点,而与上下左右四个点的连线为边,这个点与上下左右四个点连边,流量为\(1\)

正确性证明

在最小割模型中,连一条流量为\(INF\)的边意为连一条不可割边(这套路很常见的)
而与上下左右连流量为\(1\)的边,说明这是条可割的边,并且割这条边的费用为\(1\)

总结

1.源点向羊连INF的边
2.羊向汇点连INF的边
3.每个格子向上下左右连边

圆桌问题

题面

\(n\)个单位,\(m\)个桌子,每个单位有\(c_i\)个人,每张桌子能做\(w_i\)个人,每个桌子不能做同一单位的人,求是否有解和其中一种方案

建模

思路

由于一个位置都只能做一个人,所以我们比较容易想到二分图。
\(c_i\)个人拆成\(c_i\)个点然后与\(m\)张桌子连边, 但是这种方法不能限制每个桌子不能做同一单位的人这一条件,所以舍弃。
考虑每张桌子不能做同一单位的人,我们将每个单位与每张桌子连流量为\(1\)的边,那么这就很好的限制了每个桌子不能做同一单位的人这一条件。
然后我们每个单位有\(c_i\)个人,所以我们可以将源点向每个单位连流量为\(c_i\)的边,这就满足了每个单位\(c_i\)个人
同理我们也可以将每个桌子向汇点连流量为\(w_i\)的边,这也满足了每个桌子坐\(w_i\)的人

总结

1.源点向单位连c的边
2.桌子向汇点连w的边
3.每个单位和每个桌子连流量为1的边

SCOI 蜥蜴

题面

一个\(n\times{m}\)的网格中,有一些格子有石柱,石柱的高度为\(1~3\).
有一些石柱的顶上有蜥蜴,蜥蜴每次可以跳到距离不超过\(d\)的石柱上,或者跳到界外。
蜥蜴跳一次,它所在的石柱的高度就减一,如果某个石柱的高度为\(0\)了,石柱就消失,以后蜥蜴不能跳到这里。
现在要使得剩下无法逃脱的蜥蜴数最少。

建模

思路

这里有个比较重要的思想就是拆点
由于每个柱子至多被经过\(w\)次,所以我们可以将一个点分为入点和出点两个点,然后入点和出点连一条流量为\(w\)的边
这样就限制了这个点至多走\(w\)次这个条件
然后建立超级源点 \(s\)\(s\)连向所有蜥蜴 流量为\(1\)
边缘可以跳出去的向超级汇点\(t\)连一条\(INF\)的边,表示这条边可以走\(INF\)
并且我们将可以相互抵达的柱子都连流量为\(INF\)

总结

1.源点向蜥蜴连1的边
2.可以抵达的柱子向汇点连INF的边
3.边缘柱子向周围连边

代码

for (int i = 0; i < r; i ++ ) {
	cin >> ch;
	for (int j = 0; j < c; j ++ ) {
		if (ch[j] == 'L') Add (s, Hash (i, j), 1), cnt ++ ;
	}
}
for (int i = 0; i < r; i ++ ) {
	for (int j = 0; j < c; j ++ ) {
		if (a[i][j]) Add (Hash (i, j), Hash (i, j) + r * c, a[i][j]);
		if (i < d || j < d || i + d >= r || j + d >= c) Add (Hash (i, j) + r * c, t, INF);
		for (int k = 0; k < r; k ++ ) {
			for (int l = 0; l < c; l ++ ) {
				if (dis (i, j, k, l) <= d * d && a[i][j] && a[k][l] && !((i == k) && (j == l))) Add (Hash (i, j) + r * c, Hash (k, l), INF);
			}
		}
	}
}
posted @ 2020-02-04 10:26  Hock  阅读(148)  评论(0编辑  收藏  举报