[二分图&最小割]
OTL@assassain
反转源汇的模型: 给定一个二分图,同时选择集合中的两个点会有一个代价,选择每一个点有一个收益,问最大收益是多少
(即两个点在不同的集合中是有冲突关系的)
解法: 用最小割模型解决,通过反转源汇来表示冲突关系,用源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
还有一些特殊的地方需要处理,但是和反转源汇建图没有太大关系,因此不再赘述
#define MAXN 105
#include <bits/stdc++.h> using namespace std;
const int inf = 0x7fffffff, md = 19921228; int n, m, k;
bool a[MAXN][MAXN]; int h[MAXN], cnt = 1, S, T;
struct Edge { int to, nxt, w; } edge[1000010];
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 d[MAXN], que[MAXN]; bool BFS() {
int head = 0, tail = 0;
memset(d, -1, sizeof d);
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) continue;
int v = edge[i].to;
if(d[v] == -1) que[tail ++] = v, d[v] = d[u] + 1;
}
} 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("boygirl.in", "r", stdin);
freopen("boygirl.out", "w", stdout);
scanf("%d%d%d", &n, &k, &m);
int u, v;
for(int i = 1 ; i <= m ; ++ i) {
scanf("%d%d", &u, &v);
a[u][v] = true;
} T = n+n+1;
for(int i = 1 ; i <= n ; ++ i) {
addedge(S, i, 100), addedge(i+n, T, 99);
for(int j = 1 ; j <= n ; ++ j)
if(!a[i][j])addedge(i, j+n, inf);
} int fw = Dinic();
int a = fw - fw/99*99, b = fw/99 - a;
a = n-a, b = n-b; static int C[2510][2510];
static long long f[MAXN][MAXN];
memset(C, 0, sizeof C);
memset(f, 0, sizeof f); for(int i = 0 ; i <= a*b ; ++ i) {
C[i][0] = 1;
for(int j = 1 ; j <= i ; ++ j)
C[i][j] = (C[i-1][j] + C[i-1][j-1]) % md;
} for(int i = 1 ; i <= a ; ++ i) {
for(int j = 1 ; j <= b ; ++ j) {
f[i][j] = C[i*j][k];
for(int k = 1 ; k <= i ; ++ k)
for(int l = 1 ; l <= j ; ++ l)
if(i != k || l != j)
f[i][j] = (f[i][j] - f[k][l]*C[i][k]%md*C[j][l]%md + md) % md;
}
} printf("%d %d\n%lld\n", a, b, f[a][b]);
return 0;
}
[二分图&最小割]的更多相关文章
- BZOJ 3275: Number (二分图最小割)
题意 有nnn个数,其中同时满足下面两个条件的数对不能同时选,求选出一些数让和最大. 若两个数aaa,bbb同时满足以下条件,则aaa,bbb不能同时被选 存在正整数ccc,使a∗a+b∗b=c∗ca ...
- bzoj 3158 千钧一发(最小割)
3158: 千钧一发 Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 767 Solved: 290[Submit][Status][Discuss] ...
- [TJOI2013]攻击装置(网络流,最小割)
前言 网络流被hbx吊起来打 Solution 考虑一下这个走法是不是和象棋中马的走法一模一样(废话) 那么显然我每一次移动是走三次,如果将棋盘二分图染色一下,不就是每一次只能走到另一个颜色的吗? 然 ...
- 1934. [SHOI2007]善意的投票【最小割】
Description 幼儿园里有n个小朋友打算通过投票来决定睡不睡午觉.对他们来说,这个问题并不是很重要,于是他们决定发扬谦让精神.虽然每个人都有自己的主见,但是为了照顾一下自己朋友的想法,他们也可 ...
- 二分图&网络流&最小割等问题的总结
二分图基础: 最大匹配:匈牙利算法 最小点覆盖=最大匹配 最小边覆盖=总节点数-最大匹配 最大独立集=点数-最大匹配 网络流: 技巧: 1.拆点为边,即一个点有限制,可将其转化为边 BZOJ1066, ...
- POJ 2125 Destroying The Graph (二分图最小点权覆盖集+输出最小割方案)
题意 有一个图, 两种操作,一种是删除某点的所有出边,一种是删除某点的所有入边,各个点的不同操作分别有一个花费,现在我们想把这个图的边都删除掉,需要的最小花费是多少. 思路 很明显的二分图最小点权覆盖 ...
- POJ2125 Destroying The Graph 二分图 + 最小点权覆盖 + 最小割
思路来源:http://blog.csdn.net/lenleaves/article/details/7873441 求最小点权覆盖,同样求一个最小割,但是要求出割去了那些边, 只要用最终的剩余网络 ...
- 【最小割/二分图最大独立集】【网络流24题】【P2774】 方格取数问题
Description 给定一个 \(n~\times~m\) 的矩阵,每个位置有一个正整数,选择一些互不相邻的数,最大化权值和 Limitation \(1~\leq~n,~m~\leq~100\) ...
- 【LA3415 训练指南】保守的老师 【二分图最大独立集,最小割】
题意 Frank是一个思想有些保守的高中老师.有一次,他需要带一些学生出去旅行,但又怕其中一些学生在旅行中萌生爱意.为了降低这种事情发生的概率,他决定确保带出去的任意两个学生至少要满足下面四条中的一条 ...
随机推荐
- django-cms 代码研究(七)杂七杂八
实体关系图 核心对象: cms_page/cms_placeholder/cms_cmsplugin. page模型类继承关系图 CMSPlugin&Placeholder模型类继承关系图 = ...
- Spring事务传播、隔离等级
事务传播 PROPAGATION_REQUIRED 如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中.这是最常见的选择. PROPAGATION_SUPPORTS 支持当前事 ...
- VMware Snapshot 工作原理
VMware中的快照是对VMDK在某个时间点的“拷贝”,这个“拷贝”并不是对VMDK文件的复制,而是保持磁盘文件和系统内存在该时间点的状态,以便在出现故障后虚拟机能够恢复到该时间点.如果对某个虚拟机创 ...
- 《ASP.NET1200例》解决母版页报错“内容控件必须是内容页中的顶级控件,或是引用母版页的嵌套母版页。”
VS2005下,添加了母版页这个控件,我们可以讲N个页面中共同的部分放在母版页来实现,并让WEB窗体集成自我们的母版页,就可以让我们的站点具有统一的风格了.在VS2005SP1之前的版本中,我们只能创 ...
- 通过eclipse配置Spring MVC项目
上一篇刚建立了一个简单的Spring项目,其实Spring MVC是一个和Struts2一样的基于MVC设计模式的web框架,并且继承了MVC的优点,是基于请求驱动的轻量级的web框架,spring ...
- Java for LeetCode 028 Implement strStr()
Implement strStr(). Returns the index of the first occurrence of needle in haystack, or -1 if needle ...
- codeforces A. K-Periodic Array 解题报告
题目链接:http://codeforces.com/problemset/problem/371/A 题目意思:给出n和k和一个只有1或者2组成的序列,需要求出最少的改变次数,使得 n/k 组里面的 ...
- codeforces B. Routine Problem 解题报告
题目链接:http://codeforces.com/problemset/problem/337/B 看到这个题目,觉得特别有意思,因为有熟悉的图片(看过的一部电影).接着让我很意外的是,在纸上比划 ...
- java用代理访问
Properties prop = System.getProperties(); prop.setProperty("http.proxyHost", "localho ...
- 解决Unable to locate Kerberos realm
在windows环境下 将服务器上的/etc/krb5.conf 复制到<jdk-home>/jre/lib/security