LOJ6007 「网络流 24 题 - 8」 方格取数 二分图最大点权独立集
2017-12-07 12:25
459 查看
大家都很强, 可与之共勉 。
题意:在一个有 m×n 个方格的棋盘中,每个方格中有一个正整数。
现要从方格中取数,使任意2个数所在方格没有公共边,且取出的数的总和最大。试设计一个满足要求的取数算法。
题解:
求一张图的最大点权独立集。
关于概念:
二分图最大点权独立集:从一张图中找到权值和最大的点集,使得它们之间两两没有边。
二分图最小点权覆盖集:从一张图中选取一些点,使这些点覆盖所有的边,并且选出来的点的权值尽可能小。
其实二分图最大点权独立集是二分图最小点权覆盖的对偶问题。即是总权值-二分图最小点覆盖集。
而二分图最小点权覆盖集等于二分图最小割
我们把原图黑白染色以(i+j)%2,其中让白色点在左边,黑色点在右边,白色点向黑色点连边
我们只连有冲突的边,边权为+∞,对于每一个白点,S向白点连边,权值为点权v;对于每一个黑点,黑点向T连边,权值为点权v。
跑出最小割,即二分图最小点权覆盖集。然后用总权值减去就是答案。
# include <bits/stdc++.h> # define N 5010 class Network { private : struct edge { int to, w, nxt ; edge ( ) { } edge ( int to, int w, int nxt ) : to ( to ), w ( w ), nxt ( nxt ) { } } g [60010 << 1] ; int head , cur , ecnt ; int S, T , dep ; inline int dfs ( int u, int a ) { if ( u == T || ! a ) return a ; int flow = 0, v, f ; for ( int& i = cur [u] ; i ; i = g [i].nxt ) { v = g [i].to ; if ( dep [v] == dep [u] + 1 ) { f = dfs ( v, std :: min ( g [i].w, a - flow ) ) ; g [i].w -= f, g [i ^ 1].w += f ; flow += f ; if ( a == flow ) return a ; } } if ( ! flow ) dep [u] = -1 ; return flow ; } inline bool bfs ( int S, int T ) { static std :: queue < int > q ; memset ( dep, 0, sizeof ( int ) * ( T + 1 ) ) ; dep [S] = 1 ; q.push ( S ) ; while ( ! q.empty ( ) ) { int u = q.front ( ) ; q.pop ( ) ; for ( int i = head [u] ; i ; i = g [i].nxt ) { int& v = g [i].to ; if ( g [i].w && ! dep [v] ) { dep [v] = dep [u] + 1 ; q.push ( v ) ; } } } return dep [T] ; } public : Network ( ) { ecnt = 1 ; } inline void add_edge ( int u, int v, int w ) { g [++ ecnt] = edge ( v, w, head [u] ) ; head [u] = ecnt ; g [++ ecnt] = edge ( u, 0, head [v] ) ; head [v] = ecnt ; } inline void clear ( ) { ecnt = 1 ; memset ( head, 0, sizeof head ) ; } inline int dinic ( int S, int T ) { this -> S = S, this -> T = T ; int rt = 0 ; while ( bfs ( S, T ) ) { memcpy ( cur, head, sizeof ( int ) * ( T + 1 ) ) ; rt += dfs ( S, 0x3f3f3f3f ) ; } return rt ; } } Lazer ; # define id(i, j) ((i-1)*m+j) const int dx [] = { 1, -1, 0, 0 } ; const int dy [] = { 0, 0, 1, -1 } ; int main ( ) { int n, m ; scanf ( "%d%d", & n, & m ) ; const int S = n * m + 1, T = n * m + 2 ; int sum ( 0 ) ; for ( int i = 1 ; i <= n ; ++ i ) for ( int j = 1 ; j <= m ; ++ j ) { int v ; scanf ( "%d", & v ) ; sum += v ; if ( ( i + j ) & 1 ) Lazer.add_edge ( S, id ( i, j ), v ) ; else Lazer.add_edge ( id ( i, j ), T, v ) ; if ( ( i + j ) & 1 ) { for ( int k = 0 ; k < 4 ; ++ k ) { int x = i + dx [k], y = j + dy [k] ; if ( x >= 1 && x <= n && y >= 1 && y <= m ) { Lazer.add_edge ( id ( i, j ), id ( x, y ), 0x3f3f3f3f ) ; } } } } int mincut = Lazer.dinic ( S, T ) ; printf ( "%d\n", sum - mincut ) ; return 0 ; }
相关文章推荐
- loj6007「网络流 24 题」方格取数 最大点权独立集
- 【网络流24题】方格取数(二分图染色+最大权独立点集+最小割)
- 【loj】#6007. 「网络流 24 题」方格取数(二分图最大点权独立集)
- [网络流24题]骑士共存问题 二分图/最大点权独立集
- [网络流24题]方格取数 最大点权独立集
- 【网络流24题】骑士共存问题(二分图染色+最大权独立子集+最小割)
- [网络流24题] 09 方格取数问题 (二分图点权最大独立集,最小割)
- 【网络流24题】最长k可重区间集(最大费用流+二分图)
- ★ 方格取数3 二分图的最大点权独立集
- 线性规划与网络流24题之分配问题 最大费用最大流、最小费用最大流、二分图的最佳匹配
- 【网络流24题】方格取数问题(最大流)
- 【codevs1907】【方格取数3】二分图最大带权独立集
- 独立最小【网络流第五弹】最大点权独立集 ——HDU 1569 方格取数(2)
- [网络流24题] 飞行员配对方案问题 最大流 二分图最大匹配
- [网络流24题] 方格取数问题 (最大点权独立集)
- [网络流24题] 24 骑士共存(二分图最大独立集,网络最小割)
- hdu 1569 方格取数(2) 网络流--最大点权独立集
- HDU 1565 方格取数(1) 二分图最大点权独立集
- 【网络流24题】No.7 试题库问题 (最大流,二分图多重匹配)
- loj6000 「网络流 24 题」搭配飞行员(二分图最大匹配)