Description

给你一个m*n的格子的棋盘,每个格子里面有一个非负数。 从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取数所在的2个格子不能相邻,并且取出的数的和最大。
 

Input

包括多个测试实例,每个测试实例包括2整数m,n和m*n个非负数(m<=50,n<=50)
 

Output

对于每个测试实例,输出可能取得的最大的和

题目大意:这么短还中文就没大意了,唯一要注意的就是输入的第一个是行第二个是列……

思路:这题为最大权独立集(所选的点之间都没有边)。建立一个最大流的二分图,i+j为偶数的放左边,源点S连一条边到它,容量为格子里的数,其余放右边,连一条边到汇点T,容量还是格子里的数,相邻的都从左到右连一条边,容量为无穷大。所有数字之和减去最大流即为答案。

小证明:这样构图求出的最大流为最小权覆盖集(所有边至少被一个点覆盖),详见POJ 3308 Paratroopers(最大流最小割の最小点权覆盖)

而最小权覆盖集与最大权独立集是对偶图,把最小权覆盖集里的点都取反,就可以得到一个最大权独立集,所以总权 = 最小权覆盖集 + 最大权独立集。详见二分图中的对偶问题

代码(15MS):

 #include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std; const int MAXN = ;
const int MAXE = ;
const int INF = 0x3fff3fff; struct SAP {
int head[MAXN], dis[MAXN], pre[MAXN], cur[MAXN], gap[MAXN];
int to[MAXE], next[MAXE], flow[MAXE];
int n, st, ed, ecnt; void init() {
memset(head, , sizeof(head));
ecnt = ;
} void add_edge(int u, int v, int c) {
to[ecnt] = v; flow[ecnt] = c; next[ecnt] = head[u]; head[u] = ecnt++;
to[ecnt] = u; flow[ecnt] = ; next[ecnt] = head[v]; head[v] = ecnt++;
//printf("%d->%d flow = %d\n", u, v, c);
} void bfs() {
memset(dis, 0x3f, sizeof(dis));
queue<int> que; que.push(ed);
dis[ed] = ;
while(!que.empty()) {
int u = que.front(); que.pop();
++gap[dis[u]];
for(int p = head[u]; p; p = next[p]) {
int &v = to[p];
if(flow[p ^ ] && dis[v] > n) {
dis[v] = dis[u] + ;
que.push(v);
}
}
}
} int Max_flow(int ss, int tt, int nn) {
st = ss; ed = tt; n = nn;
int ans = , minFlow = INF, u;
for(int i = ; i <= n; ++i) {
cur[i] = head[i];
gap[i] = ;
}
u = pre[st] = st;
bfs();
while(dis[st] < n) {
bool flag = false;
for(int &p = cur[u]; p; p = next[p]) {
int &v = to[p];
if(flow[p] && dis[u] == dis[v] + ) {
flag = true;
minFlow = min(minFlow, flow[p]);
pre[v] = u;
u = v;
if(u == ed) {
ans += minFlow;
while(u != st) {
u = pre[u];
flow[cur[u]] -= minFlow;
flow[cur[u] ^ ] += minFlow;
}
minFlow = INF;
}
break;
}
}
if(flag) continue;
int minDis = n - ;
for(int p = head[u]; p; p = next[p]) {
int &v = to[p];
if(flow[p] && minDis > dis[v]) {
minDis = dis[v];
cur[u] = p;
}
}
if(--gap[dis[u]] == ) break;
gap[dis[u] = minDis + ]++;
u = pre[u];
}
return ans;
}
} G; int n, m;
int mat[][]; int main() {
while(scanf("%d%d", &n, &m) != EOF) {
for(int i = ; i <= n; ++i)
for(int j = ; j <= m; ++j) scanf("%d", &mat[i][j]);
G.init();
int ss = n * m + , tt = n * m + ;
int cnt = , sum = ;
for(int i = ; i <= n; ++i) {
for(int j = ; j <= m; ++j) {
++cnt; sum += mat[i][j];
if((i + j) & ) {
G.add_edge(ss, cnt, mat[i][j]);
if(j != ) G.add_edge(cnt, cnt - , INF);
if(i != ) G.add_edge(cnt, cnt - m, INF);
if(j != m) G.add_edge(cnt, cnt + , INF);
if(i != n) G.add_edge(cnt, cnt + m, INF);
}
else G.add_edge(cnt, tt, mat[i][j]);
}
}
printf("%d\n", sum - G.Max_flow(ss, tt, tt));
}
}

HDU 1569 方格取数(2)(最大流最小割の最大权独立集)的更多相关文章

  1. HDU 1569 方格取数(2) (最小割)

    方格取数(2) Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Su ...

  2. 网络流(最大流) HDU 1565 方格取数(1) HDU 1569 方格取数(2)

      HDU 1565 方格取数(1) 给你一个n*n的格子的棋盘,每个格子里面有一个非负数.从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取的数所在的2个格子不能相邻,并且取出的数的 ...

  3. HDU 1569 方格取数(2)

    方格取数(2) Time Limit: 5000ms Memory Limit: 32768KB This problem will be judged on HDU. Original ID: 15 ...

  4. HDU 1569 - 方格取数(2) - [最大点权独立集与最小点权覆盖集]

    嗯,这是关于最大点权独立集与最小点权覆盖集的姿势,很简单对吧,然后开始看题. 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1569 Time Limi ...

  5. HDU 1565 - 方格取数(1) - [状压DP][网络流 - 最大点权独立集和最小点权覆盖集]

    题目链接:https://cn.vjudge.net/problem/HDU-1565 Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32 ...

  6. HDU 1565 1569 方格取数(最大点权独立集)

    HDU 1565 1569 方格取数(最大点权独立集) 题目链接 题意:中文题 思路:最大点权独立集 = 总权值 - 最小割 = 总权值 - 最大流 那么原图周围不能连边,那么就能够分成黑白棋盘.源点 ...

  7. [HDU 1565+1569] 方格取数

    HDU 1565 方格取数(1) Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others ...

  8. HDU 1565&1569 方格取数系列(状压DP或者最大流)

    方格取数(2) Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total S ...

  9. HDU 1565 方格取数(1) 轮廓线dp

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1565 方格取数(1) Time Limit: 10000/5000 MS (Java/Others) ...

随机推荐

  1. ES5 实现 ES6 的 class以及extends

    ts中是这样的 class Greeter { greeting:string; constructor(message:string){ this.greeting = message; } gre ...

  2. app后端api设计【转】

    博客:https://blog.csdn.net/newjueqi/article/details/44037011 app和后端的交互,一般都是通过后端提供的api实现.api的设计,估计很多刚进入 ...

  3. 【一】调通单机版的thrift-python版本

    开发步骤说明 [任务1]调通单机版的thrift-python版本 [任务1]调通单机版的thrift-python版本 安装thrift 创建thrift模块文件并编译 开发python版的clie ...

  4. python之内存与编码的那点事

    一.初始编码 ASCII 码不支持中文 是py2版本中的默认编码 ​Unicode 万国码, 英文使用16位(即两个字节​),中文使用32位(四个字节) ​utf-8 美国最少使用八位(1字节), 欧 ...

  5. linux 下的torrent下载器qBitTorrent

    BT下载利器--Qbittorrent完全攻 Ubuntu使用命令安装qBittorrent的方法 源码下载

  6. Python3爬虫(十六) pyspider框架

    Infi-chu: http://www.cnblogs.com/Infi-chu/ 一.pyspider介绍1.基本功能 提供WebUI可视化功能,方便编写和调试爬虫 提供爬取进度监控.爬取结果查看 ...

  7. ChipScope Pro Inserter - "ERROR:NgdBuild:924 - bidirect pad net '<oDRAM0_A>' is driving non-buffer primitives

    解决方案: Using a IOBUF signal as a trigger for the ILA Inserter flow will cause a NGDBuild error. These ...

  8. ld: i386 架构于输入文件 bar.o 与 i386:x86-64 输出不兼容

    报错:ld: i386 架构于输入文件 foo.o 与 i386:x86-64 输出不兼容 或者:ld: i386 architecture of input file `foo.o' is inco ...

  9. 西安Uber优步司机奖励政策(12月14日到12月20日)

    滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单:http://www.cnblogs.com/mfry ...

  10. 3551: [ONTAK2010]Peaks加强版

    3551: [ONTAK2010]Peaks加强版 https://www.lydsy.com/JudgeOnline/problem.php?id=3551 分析: kruskal重构树 +  倍增 ...