题目链接:https://vjudge.net/problem/HDU-1569

方格取数(2)

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 6876    Accepted Submission(s): 2198

Problem Description
给你一个m*n的格子的棋盘,每个格子里面有一个非负数。
从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取数所在的2个格子不能相邻,并且取出的数的和最大。
 
Input
包括多个测试实例,每个测试实例包括2整数m,n和m*n个非负数(m<=50,n<=50)
 
Output
对于每个测试实例,输出可能取得的最大的和
 
Sample Input
3 3
75 15 21
75 15 28
34 70 5
 
Sample Output
188
 
Author
ailyanlu
 
Source

题解:

1.将n*m的格子建模成二分图。

2.在二分图的基础上添加源点S和汇点T, 然后从S向所有X集合中的点连一条边, 所有Y集合中的点向T连一条边, 容量均为该点的权值。

3.X集合的结点与Y集合的结点之间的边的容量为无穷大。在此题中,如果是格子相邻,就需要连边,且是X-->Y。

4.因此,对于该图中的任意一个割, 将割中的边所对应的结点删掉,就是一个符合条件的解,权值和为所有权和减去割的容量。

5.根据4可得:只要求出最小割, 就能求出最大权值和独立集。

代码如下:

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstring>
  4. #include <algorithm>
  5. #include <vector>
  6. #include <cmath>
  7. #include <queue>
  8. #include <stack>
  9. #include <map>
  10. #include <string>
  11. #include <set>
  12. using namespace std;
  13. typedef long long LL;
  14. const int INF = 2e9;
  15. const LL LNF = 9e18;
  16. const int mod = 1e9+;
  17. const int MAXM = 1e5+;
  18. const int MAXN = +;
  19.  
  20. struct Edge
  21. {
  22. int to, next, cap, flow;
  23. }edge[MAXM];
  24. int tot, head[MAXN];
  25. int gap[MAXN], dep[MAXN], pre[MAXN], cur[MAXN];
  26.  
  27. void init()
  28. {
  29. tot = ;
  30. memset(head, -, sizeof(head));
  31. }
  32.  
  33. void add(int u, int v, int w)
  34. {
  35. edge[tot].to = v; edge[tot].cap = w; edge[tot].flow = ;
  36. edge[tot].next = head[u]; head[u] = tot++;
  37. edge[tot].to = u; edge[tot].cap = ; edge[tot].flow = ;
  38. edge[tot].next = head[v]; head[v] = tot++;
  39. }
  40.  
  41. int sap(int start, int end, int nodenum)
  42. {
  43. memset(dep, , sizeof(dep));
  44. memset(gap, , sizeof(gap));
  45. memcpy(cur, head, sizeof(head));
  46. int u = pre[start] = start, maxflow = ,aug = INF;
  47. gap[] = nodenum;
  48. while(dep[start]<nodenum)
  49. {
  50. loop:
  51. for(int i = cur[u]; i!=-; i = edge[i].next)
  52. {
  53. int v = edge[i].to;
  54. if(edge[i].cap-edge[i].flow && dep[u]==dep[v]+)
  55. {
  56. aug = min(aug, edge[i].cap-edge[i].flow);
  57. pre[v] = u;
  58. cur[u] = i;
  59. u = v;
  60. if(v==end)
  61. {
  62. maxflow += aug;
  63. for(u = pre[u]; v!=start; v = u,u = pre[u])
  64. {
  65. edge[cur[u]].flow += aug;
  66. edge[cur[u]^].flow -= aug;
  67. }
  68. aug = INF;
  69. }
  70. goto loop;
  71. }
  72. }
  73. int mindis = nodenum;
  74. for(int i = head[u]; i!=-; i = edge[i].next)
  75. {
  76. int v=edge[i].to;
  77. if(edge[i].cap-edge[i].flow && mindis>dep[v])
  78. {
  79. cur[u] = i;
  80. mindis = dep[v];
  81. }
  82. }
  83. if((--gap[dep[u]])==)break;
  84. gap[dep[u]=mindis+]++;
  85. u = pre[u];
  86. }
  87. return maxflow;
  88. }
  89.  
  90. int n, m, g[][];
  91. int main()
  92. {
  93. while(scanf("%d%d", &n, &m)!=EOF)
  94. {
  95. int sum = ;
  96. for(int i = ; i<n; i++)
  97. for(int j = ; j<m; j++)
  98. scanf("%d", &g[i][j]), sum += g[i][j];
  99.  
  100. int start = n*m, end = n*m+;
  101. init();
  102. for(int i = ; i<n; i++)
  103. for(int j = ; j<m; j++)
  104. {
  105. if((i+j)%)
  106. {
  107. add(start, i*m+j, g[i][j]);
  108. if(i!=) add(i*m+j, (i-)*m+j, INF);
  109. if(i!=n-) add(i*m+j, (i+)*m+j, INF);
  110. if(j!=) add(i*m+j, i*m+j-, INF);
  111. if(j!=m-) add(i*m+j, i*m+j+, INF);
  112. }
  113. else
  114. add(i*m+j, end, g[i][j]);
  115. }
  116.  
  117. sum -= sap(start, end, n*m+);
  118. printf("%d\n", sum);
  119. }
  120. }

HDU1569 方格取数(2) —— 二分图点带权最大独立集、最小割最大流的更多相关文章

  1. HDU1565 方格取数(1) —— 状压DP or 插头DP(轮廓线更新) or 二分图点带权最大独立集(最小割最大流)

    题目链接:https://vjudge.net/problem/HDU-1565 方格取数(1) Time Limit: 10000/5000 MS (Java/Others)    Memory L ...

  2. hdu1569 方格取数(2) 最大点权独立集=总权和-最小点权覆盖集 (最小点权覆盖集=最小割=最大流)

    /** 转自:http://blog.csdn.net/u011498819/article/details/20772147 题目:hdu1569 方格取数(2) 链接:https://vjudge ...

  3. hdu1569 方格取数 求最大点权独立集

    题意:一个方格n*m,取出一些点,要求两两不相邻,求最大和.思路:建图,相邻的点有一条边,则建立了一个二分图,求最大点权独立集(所取点两两无公共边,权值和最大),问题转化为求总权和-最小点权覆盖集(点 ...

  4. BZOJ 1475 方格取数(二分图最大点权独立集)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1475 [题目大意] 给出一个n*n的方格,从中取一些不相邻的数字,使得和最大 [题解] ...

  5. 洛谷 - P2774 - 方格取数问题 - 二分图最大独立点集 - 最小割

    https://www.luogu.org/problemnew/show/P2774 把两个相邻的节点连边,这些边就是要方便最小割割断其他边存在的,容量无穷. 这种类似的问题的话,把二分图的一部分( ...

  6. luogu2774 方格取数问题 二分图最小权点覆盖集

    题目大意:在一个有 m*n 个方格的棋盘中,每个方格中有一个正整数.现要从方格中取数,使任意 2 个数所在方格没有公共边,输出这些数之和的最大值. 思路:这种各个点之间互相排斥求最大值的题,往往需要利 ...

  7. Luogu_2774 方格取数问题

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

  8. HDU 1569 方格取数(2)

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

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

    Description 给定一个 \(n~\times~m\) 的矩阵,每个位置有一个正整数,选择一些互不相邻的数,最大化权值和 Limitation \(1~\leq~n,~m~\leq~100\) ...

随机推荐

  1. 空指针问题(java.lang.NullPointerException)

    在Java中对值为null的指针调用任何方法,就会引发空指针异常(java.lang.NullPointerException).空指针异常绝对是Java中最难查找和调试的一种异常,你永远无法得到任何 ...

  2. ReSharper7.1.25.234 注册机

    经常用vs做开发的人都知道,ReSharper是vistual studio必备插件之一.他的智能提示,智能感知,.net底层方法查看,测试等都非常方便,给程序员带来了巨大的效率. 但众所周知ReSh ...

  3. oracle怎么查看表空间里有哪些表

    select TABLE_NAME,TABLESPACE_NAME from dba_tables where TABLESPACE_NAME='表空间名'; 注意:表空间名要大写

  4. Android数据存储之SQLite数据库

    Android数据存储 之SQLite数据库简介 SQLite的相关知识,并结合Java实现对SQLite数据库的操作. SQLite是D.Richard Hipp用C语言编写的开源嵌入式数据库引擎. ...

  5. 树莓派学习笔记——I2C设备载入和速率设置

    原文:http://blog.csdn.net/xukai871105/article/details/18234075 1.载入设备 方法1——临时载入设备 sudo modprobe -r i2c ...

  6. IntelliJ IDEA常用统一设置(Linux/Mac/Windows)

    前言:如果说VS是宇宙超级无敌第一大开发工具,那么IDEA是当之无愧的第二大开发工具,将来有机会把VS干掉. 说明:除了以下说明的配置地方外,其它尽量保持默认,这样有利于团队代码风格的统一. 运行VM ...

  7. go语言学习之路三:切片

    前面讲了变量的有关知识,这里对于其他的数据类型就不多作介绍,(和C差不多),因此重点来讨论下切片. 一.切片是引用类型,这里要稍微介绍两个概念:值类型,构造类型和引用类型 1.值类型:是一种由类型的实 ...

  8. cut printf awk sed grep笔记

    名称 作用 参数 实例 cut 截取某列,可指定分隔 -f 列号 -d 分隔符 cut -d ":" -f 1, 3 /etc/passwd 截取第一列和第三列 printf pr ...

  9. Linux内核配置选项

    http://blog.csdn.net/wdsfup/article/details/52302142 http://www.manew.com/blog-166674-12962.html Gen ...

  10. 【SQL Server 学习系列】-- 获取字符串中出现某字符的次数及字符某次出现的下标

    ) = '1_BB_CC_DD_AA_EE_YY_WW_HH_GG' --// 1. 获取下划线在字符串中出现的次数 SELECT LEN(@Str) - LEN(REPLACE(@Str, '_', ...