[二分图&最小割]

[email protected]

反转源汇的模型:

给定一个二分图,同时选择集合中的两个点会有一个代价,选择每一个点有一个收益,问最大收益是多少

(即两个点在不同的集合中是有冲突关系的)

解法: 用最小割模型解决,通过反转源汇来表示冲突关系,用源S汇T表示选或不选,左边的黑点向S连黑点选择的收益(如果这条边割掉了就代表没有选择这个黑点,要减掉这个代价),向T连黑点不选择的收益(可以没有)。右边的白点向S连白点不选择的收益,向T连白点选择的收益(此时把S,T和上述反转了一下)。那么原图中两个点共同选择的代价就是在网络流图中直接连原来的权值即可

其实模型和另外一个模型很有对比意义,即最大权闭合子图

模型是给定一个二分图,选择其中一个点会有另一个点必须被选择(这时可以用inf的边来表示冲突关系),选择的收益有正有负(也可以看做有加有减),问最大收益。

那么此时两个点在相同的集合中是没有矛盾的,在不同的集合中是有代价的,此时不需要反转源汇,直接建图跑最小割就可以了

最大利益 = 所有点正权值之和 - 最小割

[国家集训队2011]圈地计划 网格图黑白染色,注意连双向边

#define MAXN 110
#include <bits/stdc++.h>

using namespace std;
const int inf = 0x7fffffff / 2;
const int dx[4] = {-1, 1, 0, 0}, dy[4] = {0, 0, -1, 1};

int n, m, S, T, a[MAXN][MAXN], b[MAXN][MAXN], c[MAXN][MAXN];
int h[MAXN*MAXN], cnt = 1;
struct Edge { int to, nxt, w; } edge[2000010];
void addedge(int u, int v, int w) {
	edge[++ cnt] = (Edge){v, h[u], w}; h[u] = cnt;
	edge[++ cnt] = (Edge){u, h[v], 0}; h[v] = cnt;
}

int que[MAXN*MAXN], d[MAXN*MAXN];
bool BFS() {
	int head = 0, tail = 0;
	for(int i = S ; i <= T ; ++ i) d[i] = -1;
	que[tail ++] = S, d[S] = 0;
	while(head != tail) {
		int u = que[head ++];
		for(int i = h[u] ; i ; i = edge[i].nxt) {
			if(edge[i].w == 0) continue;
			int v = edge[i].to;
			if(d[v] == -1) d[v] = d[u] + 1, que[tail ++] = v;
		}
	} return d[T] != -1;
}

int DFS(int x, int a) {
	if(x == T || a == 0) return a;
	int used = 0, f;
	for(int i = h[x] ; i ; i = edge[i].nxt) {
		int v = edge[i].to;
		if(d[v] == d[x] + 1) {
			f = DFS(v, min(a-used, edge[i].w));
			edge[i].w -= f;
			edge[i^1].w += f;
			used += f;
			if(used == a) return used;
		}
	}
	if(!used)d[x] = -1;
	return used;
}

int Dinic() {
	int ret = 0;
	while(BFS())
		ret += DFS(S, inf);
	return ret;
}

int main() {
	freopen("nt2011_land.in", "r", stdin);
	freopen("nt2011_land.out", "w", stdout);
	scanf("%d%d", &n, &m);
	for(int i = 1 ; i <= n ; ++ i)
		for(int j = 1 ; j <= m ; ++ j)
			scanf("%d", &a[i][j]);
	for(int i = 1 ; i <= n ; ++ i)
		for(int j = 1 ; j <= m ; ++ j)
			scanf("%d", &b[i][j]);
	for(int i = 1 ; i <= n ; ++ i)
		for(int j = 1 ; j <= m ; ++ j)
			scanf("%d", &c[i][j]);
	static int id[MAXN][MAXN], idfclock = 0;
	for(int i = 1 ; i <= n ; ++ i)
		for(int j = 1 ; j <= m ; ++ j)
			id[i][j] = ++ idfclock;
	S = 0, T = ++ idfclock;
	for(int i = 1 ; i <= n ; ++ i)
		for(int j = 1 ; j <= m ; ++ j) {
			if(i + j & 1) {
				addedge(S, id[i][j], a[i][j]);
				addedge(id[i][j], T, b[i][j]);
			}
			else {
				addedge(S, id[i][j], b[i][j]);
				addedge(id[i][j], T, a[i][j]);
			}
			for(int k = 0 ; k < 4 ; ++ k) {
				int x = i + dx[k], y = j + dy[k];
				if(id[x][y])addedge(id[i][j], id[x][y], c[i][j] + c[x][y]);
			}
		}
	int ans = 0;
	for(int i = 1 ; i <= n ; ++ i)
		for(int j = 1 ; j <= m ; ++ j) {
			int cn = 0;
			for(int k = 0 ; k < 4 ; ++ k) {
				int x = i + dx[k], y = j + dy[k];
				if(id[x][y]) cn ++;
			}
			ans += a[i][j] + b[i][j] + c[i][j] * cn;
		}

	printf("%d\n", ans - Dinic());
	return 0;
}

[国家集训队2011]男生女生

求一个最大的二分图的子图,使得左边的每一个点向右边的每一个点都有边相连(第一问)

转化成最小割模型后,表示的冲突关系是左边选择一个点,右边和它没有边相连的点就不能选择。

选择一个点的收益为1,不选择的收益为0

那么这道题的建图就是从S->左边的点,右边的点->T连边,中间因为永远不能割断所以边权为inf

还有一些特殊的地方需要处理,但是和反转源汇建图没有太大关系,因此不再赘述

时间: 2025-01-11 10:25:59

[二分图&最小割]的相关文章

bzoj 3158 千钧一发(最小割)

3158: 千钧一发 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 767  Solved: 290[Submit][Status][Discuss] Description Input 第一行一个正整数N. 第二行共包括N个正整数,第 个正整数表示Ai. 第三行共包括N个正整数,第 个正整数表示Bi. Output 共一行,包括一个正整数,表示在合法的选择条件下,可以获得的能量值总和的最大值. Sample Input 4 3 4 5 12 9

【Codevs1922】骑士共存问题(最小割,二分图最大匹配)

题意: 在一个n*n个方格的国际象棋棋盘上,马(骑士)可以攻击的棋盘方格如图所示.棋盘上某些方格设置了障碍,骑士不得进入. 对于给定的n*n个方格的国际象棋棋盘和障碍标志,计算棋盘上最多可以放置多少个骑士,使得它们彼此互不攻击. n<=200,m<=n^2 思路:经典的二分图最大匹配问题,采用黑白点染色的思想. 如果按照相邻点黑白不同染色,可以发现每次跳到的点必定与现在所在点不同色,二分图最大匹配即可. 这里用最小割来解决,因为不能允许任何黑白点之间的任何一条边有流量,符合最小割的思想. 1

hdoj 3820 Golden Eggs 【双二分图构造最小割模型】

Golden Eggs Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 505    Accepted Submission(s): 284 Problem Description There is a grid with N rows and M columns. In each cell you can choose to put

二分图&amp;网络流&amp;最小割等问题的总结

二分图基础: 最大匹配:匈牙利算法 最小点覆盖=最大匹配 最小边覆盖=总节点数-最大匹配 最大独立集=点数-最大匹配 网络流: 带下界网络流 最小割问题的总结: *意义 1.加inf的边表示不能被割,通常用于体现某个点必须属于某个集合 连边(s,u,w)代表如果u不在s割的话需要付出代价w 2.连边(u,v,w)代表如果u在s割,v在t割需要付出代价w 但注意,如果u在t割,v在s割是不需要付出代价的. 那么如果连边(u,v,w)以及(v,u,w)则说明当u与v所属割不同的时候需要付出代价w *

POJ 3308 Paratroopers (二分图最小点权覆盖 -&gt; 最小割 -&gt; 最大流)

POJ 3308 Paratroopers 链接:http://poj.org/problem?id=3308 题意:有一个N*M的方阵,有L个伞兵降落在方阵上.现在要将所有的伞兵都消灭掉,可以在每行每列装一个高射炮,如果在某行(某列)装上高射炮之后,能够消灭所有落在该行(该列)的伞兵.每行每列安高射炮有费用,问如何安装能够使得费用之积最小. 思路:首先题目要求乘积最小,将乘积对e取对数,会发现就变成了求和.然后抽象出一个二分图,每一行是x部的一个点,每个点有权值,权值为费用取ln.每一列是y部

POJ2125 Destroying The Graph 二分图 + 最小点权覆盖 + 最小割

思路来源:http://blog.csdn.net/lenleaves/article/details/7873441 求最小点权覆盖,同样求一个最小割,但是要求出割去了那些边, 只要用最终的剩余网络进行一次遍历就可以了,比较简单. 建图:同样是一个二分图,左边的点代表去掉出边, 右边的点代表去掉入边(小心别弄混),左边去掉出边的点与源点相连, 容量为wi- . 然后更据给出的弧进行连线,权值为INF 使用很好理解的EK算法:(360MS) //#pragma comment(linker, "

二分图最小点权覆盖 二分图最大权独立集 方格取数 最小割

二分图最小点权覆盖: 每一条边 (u, v) 都是一个限制条件, 要求 u 和 v 不能同时取得. 我们考虑先取得所有的, 然后减去最小的点权. 建立原点 S , 连向二分图左边的所有点, 与 S 连通的意义是左边的点被选择了, 或者右边的点没有被选择. 建立汇点 T , 二分图右边的所有点连向它, 与 T 连通的意义是左边的点没有被选择, 或者右边的点被选择了. 利用最小割最大流定理, 我们跑最大流, 再根据最后一次 BFS 得出的情报构造方案. 定理 覆盖集与独立集互补. 证明 即证明覆盖集

734. [网络流24题] 方格取数问题 二分图点权最大独立集/最小割/最大流

?问题描述:在一个有m*n 个方格的棋盘中,每个方格中有一个正整数.现要从方格中取数,使任意2 个数所在方格没有公共边,且取出的数的总和最大.试设计一个满足要求的取数算法.?编程任务:对于给定的方格棋盘,按照取数要求编程找出总和最大的数.?数据输入:由文件grid.in提供输入数据.文件第1 行有2 个正整数m和n,分别表示棋盘的行数和列数.接下来的m行,每行有n个正整数,表示棋盘方格中的数. [问题分析] 二分图点权最大独立集,转化为最小割模型,从而用最大流解决. [建模方法] 首先把棋盘黑白

UVA 11419 SAM I AM (二分图,最小割)

http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2414 Problem C SAM I AM Input: Standard Input Output: Standard Output The world is in great danger!! Mental's forces have returned to Earth to eradi