题目大意:在一个有 m*n 个方格的棋盘中,每个方格中有一个正整数。现要从方格中取数,使任意 2 个数所在方格没有公共边,输出这些数之和的最大值。

思路:这种各个点之间互相排斥求最大值的题,往往需要利用上网络流最小割的性质。我们把方格中的所有数字都选上,看看把哪些格子抠掉,能使数值和的减少量最少。

每个格子看作一个节点,其向四周的格子代表的节点连边。现要求一个节点的集合,使得这些点与所有边相连,求点权之和最小值。这就是最小权点覆盖集问题。

要想使该问题有解,往往要将图中的节点分为两个集合,一个集合内的任意两个节点之间没有边相连,也就是说图中所有边两头的节点必须属于不同的集合。解决该问题方法为将S与一个集合中的所有点相连,将另一个集合中的所有点与汇点相连,原图中的边容量设为无穷大,然后跑一遍最大流即可。

理解:每条连接两个集合的边两边的节点我们只要选一个抠掉,两个集合即可彻底分开。这条边的容量是无穷大,即可保证两个 连接两个集合的边的两端节点 与 源汇 连的边中 只会容量小的那个满流,表示选择了这条节点。这样,此时的最大流(最小割)便是最小点权之和。

本题中,我们发现如果把方格按照国际象棋棋盘那样的方式决定节点的集合,恰好满足要求。

#include <cstdio>
#include <cassert>
#include <cstring>
#include <queue>
#include <algorithm>
#include <cmath>
using namespace std;#define LOOP(i, n) for(int i=1; i<=n; i++)
const int MAX_NODE = 5100, MAX_EDGE = MAX_NODE * 100, INF = 0x3f3f3f3f;struct Dinic
{struct Node;struct Edge;struct Node{Edge *Head, *DfsFrom;int Level;}_nodes[MAX_NODE];int _vCount;Node *Start, *Target;struct Edge{Node *To;Edge *Next, *Rev;int Cap;Edge(Node *to, Edge *next, int cap):To(to),Next(next),Cap(cap){}}*_edges[MAX_EDGE];int _eCount;void Init(int vCount, int sId, int tId){_vCount = vCount;Start = sId + _nodes;Target = tId + _nodes;_eCount = 0;}Edge *AddEdge(Node *from, Node *to, int cap){Edge *e = _edges[++_eCount] = new Edge(to, from->Head, cap);from->Head = e;return e;}void Build(int uId, int vId, int cap){Node *u = uId + _nodes, *v = vId + _nodes;Edge *e1 = AddEdge(u, v, cap), *e2 = AddEdge(v, u, 0);e1->Rev = e2;e2->Rev = e1;}bool Bfs(){static queue<Node*> q;LOOP(i, _vCount)_nodes[i].Level = 0;Start->Level = 1;q.push(Start);while (!q.empty()){Node *u = q.front();q.pop();for (Edge *e = u->Head; e; e = e->Next){if (!e->To->Level && e->Cap){e->To->Level = u->Level + 1;q.push(e->To);}}}return Target->Level;}int Dfs(Node *cur, int limit){if (cur == Target)return limit;if (limit == 0)return 0;int curTake = 0;for (Edge *e = cur->DfsFrom; e; cur->DfsFrom = e = e->Next){if (e->To->Level == cur->Level + 1 && e->Cap){int nextTake = Dfs(e->To, min(limit - curTake, e->Cap));e->Cap -= nextTake;e->Rev->Cap += nextTake;curTake += nextTake;}if (limit - curTake==0)break;}return curTake;}int Proceed(){int ans = 0;while (Bfs()){LOOP(i, _vCount)_nodes[i].DfsFrom = _nodes[i].Head;ans += Dfs(Start, INF);}return ans;}
}g;int main()
{
#ifdef _DEBUGfreopen("c:\\noi\\source\\input.txt", "r", stdin);
#endifconst int direct[][2] = { {-1,0},{0,1},{1,0},{0,-1} };int totCol, totRow, sId, tId, totSum = 0;static int matrix[110*110];scanf("%d%d", &totCol, &totRow);sId = totCol*totRow + 1;tId = totCol*totRow + 2;g.Init(tId, sId, tId);LOOP(col, totCol)LOOP(row, totRow){int cur = (col - 1)*totRow + row;scanf("%d", &matrix[cur]);totSum += matrix[cur];if ((row + col - 1) % 2)g.Build(sId, cur, matrix[cur]);elseg.Build(cur, tId, matrix[cur]);}LOOP(col, totCol)LOOP(row, totRow)if ((row + col -1 ) % 2){int cur = (col - 1)*totRow + row;for (int i = 0; i < 4; i++){int col2 = col + direct[i][0], row2 = row + direct[i][1];if (col2 >= 1 && col2 <= totCol&&row2 >= 1 && row2 <= totRow){int next = totRow*(col2 - 1) + row2;g.Build(cur, totRow*(col2 - 1) + row2, INF);}}}int subt = g.Proceed();printf("%d\n", totSum - subt);return 0;
}

View Code

注意:

1.判断方格的上下左右这方面,尽量分别用两个变量表示行和列。直观,不容易出错。

2.先系统连与源汇相连的边,再连两个集合间的边。错误做法:站在一个集合上,找能连到另一个集合的节点的边,将其构造,然后将令那个另一个集合的节点与汇点相连。因为一个集合的点有多条边,每次把另一个集合的节点与汇点相连造成了很多重边。

转载于:https://www.cnblogs.com/headboy2002/p/8449111.html

luogu2774 方格取数问题 二分图最小权点覆盖集相关推荐

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

    «问题描述: 在一个有m*n 个方格的棋盘中,每个方格中有一个正整数.现要从方格中取数,使任 意2 个数所在方格没有公共边,且取出的数的总和最大.试设计一个满足要求的取数算法. «编程任务: 对于给定 ...

  2. 最小权点覆盖集 与 最大权独立集

    最小权点覆盖集 一.定义 什么是点覆盖集呢?就是图中所有点的一个子集,首先他是一个点集,然后图中所有边的两个端点的其中一个都在这个点集中,就是说这个点集中包含了所有边的至少一个端点,这个点集就覆盖了所 ...

  3. POJ 2125 Destroying The Graph Acwing 2325. 有向图破坏(拆点+最小权点覆盖集)

    原题链接 POJ 2125:Destroying The Graph Acwing 2325:有向图破坏 题目大意 我们要删除一个有向图中的所有边,有两种删法,一是删除某点的所有入边,二是删除某点的所 ...

  4. hdu 3657 最大点权独立集变形(方格取数的变形最小割,对于最小割建图很好的题)...

    转载:http://blog.csdn.net/cold__v__moon/article/details/7924269 /* 这道题和方格取数2相似,是在方格取数2的基础上的变形.方格取数2解法: ...

  5. 【codevs 1902】方格取数3(最小割)

    1907 方格取数 3 时间限制: 2 s   空间限制: 256000 KB    题目等级 : 大师 Master 题目描述 Description   在一个有m*n 个方格的棋盘中,每个方格中 ...

  6. [luoguP2774] 方格取数问题(最大点权独立集)

    传送门 引入两个概念: 最小点权覆盖集:满足每一条边的两个端点至少选一个的最小权点集. 最大点权独立集:满足每一条边的两个端点最多选一个的最大权点集. 现在对网格染色,使得相邻两点颜色不同,之后把两个 ...

  7. Luogu_2774 方格取数问题

    Luogu_2774 方格取数问题 二分图最小割 第一次做这种题,对于某些强烈暗示性的条件并没有理解到. 也就是每一立刻理解到是这个图是二分图. 为什么? 横纵坐标为奇数的只会和横纵坐标为偶数的相连. ...

  8. 最小割 ---- 二分图最大独立集(集合冲突模型) ---- 骑士共存 方格取数(网络流24题)

    二分图独立集 定理: 二分图最大独立集=n - 二分图最大匹配 其实二分图独立集是特殊的一种最大权闭合子图.我们根据上文"收益"的思想,把选某个点的收益看为1,左部节点为正权点,右 ...

  9. 【网络流24题】I、 方格取数问题(二分图的最大独立集/最小割)

    I. 方格取数问题(二分图的最大独立集/最小割) [问题分析] 二分图点权最大独立集,转化为最小割模型,从而用最大流解决. [建模方法] 首先把棋盘黑白染色,使相邻格子颜色不同,所有黑色格子看做二分图 ...

最新文章

  1. 百度谷歌等联合推出机器学习基准 加速AI软硬件发展
  2. Ajax兼容处理+发送请求+接收返回信息
  3. 学会使用函数式编程的程序员(第2部分)
  4. python 删除list中的第一个元素
  5. python多边形图案_如何用matplotlib中的自定义图案填充多边形?
  6. 我喜欢的JavaScript编程风格
  7. PERL 实现微信登录
  8. 转一个网络软件开发的广告
  9. CodeForces - 224C. Bracket Sequence (栈模拟)简单做法
  10. HTTP 协议 -- 浏览器缓存机制
  11. 基于Alluxio系统的Spark DataFrame高效存储管理技术
  12. ModuleNotFoundError: No module named ‘torch.utils.serialization‘解决
  13. Android学习笔记----18_在SQLite中使用事务
  14. 【特征提取】基于matlab倒谱距离端点检测【含Matlab源码 1767期】
  15. 使用 data URI scheme 在网页中内嵌图片[转]
  16. Codejock Suite Pro _16.3.X.国内最新版来了!
  17. office2013打开出现配置进度
  18. TCL语言学习笔记一
  19. 圣思园 java se_圣思园JavaSE视频笔记
  20. 套利[题目][j2]

热门文章

  1. 【强化学习论文】柔性行为综合的扩散规划
  2. php 扫码入库软件下载,php简易扫码付教育收费系统
  3. 2020IT网吧如何建立网吧电影系统
  4. Nature子刊:研究者研制出胞内和胞外神经电信号同步采集的多模态电极
  5. 六零导航页(LyLme Spage)导航网站源码
  6. 自考本科计算机有哪些专业可以选,自考本科有什么专业可以选择
  7. 企业管理需要的启示:没有任何借口
  8. 30个顶级Python库 | 用于深度学习、自然语言处理和计算机视觉
  9. App ID注册地址
  10. 美国计算机科学硕士的学制,美国CS专业你知道多少?