题目

老C是个程序员。

作为一个懒惰的程序员,老C经常在电脑上玩方块游戏消磨时间。游戏被限定在一个由小方格排成的R行C列网格上,如果两个小方格有公共的边,就称它们是相邻的,而且有些相邻的小方格之间的公共边比较特殊。特殊的公共边排列得有很强的规律。首先规定,第1行的前两个小方格之间的边是特殊边。然后,特殊边在水平方向上每4个小方格为一个周期,在竖直方向上每2个小方格为一个周期。所有的奇数列与下一列之间都有特殊边,且所在行的编号从左到右奇偶交替。

下图所示是一个R=C=8的网格,蓝色标注的边是特殊边。首先,在第1行,第1列和第2列之间有一条特殊边。因为竖直方向周期为2,所以所有的奇数行,第1列和第2列之间都有特殊边。因为水平方向周期为4,所以所有奇数行的第5列和第6列之间也有特殊边,如果网格足够大,所有奇数行的第9列和第10列、第13列和第14列之间都有特殊边。因为所有的奇数列和下一列之间都有特殊边,所以第3列和第4列、第7列和第8列之间也有特殊边,而所在行的编号从左到右奇偶交替,所以它们的特殊边在偶数行。如果网格的规模更大,我们可以用同样的方法找出所有的特殊边。

网格的每个小方格刚好可以放入一个小方块,在游戏的一开始,有些小方格已经放上了小方块,另外的小方格没有放。老C很讨厌下图所示的图形,如果他发现有一些小方块排列成了它讨厌的形状(特殊边的位置也要如图中所示),就很容易弃疗,即使是经过任意次旋转、翻转后排列成讨厌的形状,老C也同样容易弃疗。

为了防止弃疗,老C决定趁自己还没有弃疗,赶紧移除一些格子里小方块,使得剩下的小方块不能构成它讨厌的形状。但是游戏里每移除一个方块都是要花费一些金币的,每个方块需要花费的金币有多有少参差不齐。老C当然希望尽可能少的使用游戏里的金币,但是最少要花费多少金币呢?老C懒得思考,就把这个问题交给你了。

输入格式

第一行有3个正整数C,R,n,表示C列R行的网格中,有n个小方格放了小方块。接下来n行,每行3个正整数x,y,w,表示在第x列第y行的小方格里放了小方块,移除它

需要花费w个金币。保证不会重复,且都在网格范围内。

输出格式

输出一行,包含一个整数,表示最少花费的金币数量。

输入样例

3 3 7

1 1 10

1 2 15

1 3 10

2 1 10

2 2 10

2 3 10

3 1 10

输出样例

15

提示

【输入输出样例 2 说明】 如图所示。容易发现,如果不移除第1列第2行的

小方块,则至少要移除两个小方块,才能不包含老 C 讨厌的图形,花费至少20个金币;而删除第1列第2行 的小方块后,原有的讨厌图形全都不存在了,只需要 花费15个金币。

【数据规模与约定】

对于第 1~2 个测试点,1 ≤ C, R ≤ 100, 1 ≤ n ≤ 20;

对于第 3~6 个测试点,1 ≤ C, R ≤ 10^5, 2000 ≤ n ≤ 5000,数据有梯度;

对于第 7~10 个测试点,1 ≤ C, R ≤ 10^5, 30000 ≤ n ≤ 10^5,数据有梯度;

对于所有测试点,1 ≤ C, R, n ≤ 10^5, 1 ≤ w ≤ 10^4。

题解

又是一道神仙观察题,,,

观察图形,如果我们设与特殊边相邻的格子为中间格,与中间格相邻的其它格子成为相邻格

一个相邻格属于与它相邻的中间格

我们发现,一个图形不合法,当且仅当两个不属于同一个中间格的相邻格联通

考虑最小割解决

我们对图二分染色,

每个中间格和其相邻格,白点连边向黑点,流量inf

然后S向白点的相邻格连边,流量为费用

黑点的相邻格向T连边,流量为费用

然后相邻的两个中间格,其中的黑点向白点连边,流量为其中较小费用

为使所有相邻格不连通,要么去掉联通的相邻格的一个,此时割源汇点的边

要么直接去掉中间点的一个,此时割中间点的边

跑一遍最大流就可以求出了

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<algorithm>
  4. #define LL long long int
  5. #define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
  6. #define REP(i,n) for (int i = 1; i <= (n); i++)
  7. using namespace std;
  8. const int maxn = 100005,maxm = 1000005,INF = 1000000000;
  9. inline int read(){
  10. int out = 0,flag = 1; char c = getchar();
  11. while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
  12. while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
  13. return out * flag;
  14. }
  15. int h[maxn],ne = 2;
  16. struct EDGE{int to,nxt,f;}ed[maxm];
  17. inline void build(int u,int v,int w){
  18. ed[ne] = (EDGE){v,h[u],w}; h[u] = ne++;
  19. ed[ne] = (EDGE){u,h[v],0}; h[v] = ne++;
  20. }
  21. int q[maxn],head,tail,d[maxn],vis[maxn],cur[maxn],used[maxn],S,T,now;
  22. bool bfs(){
  23. vis[S] = now; q[head = tail = 1] = S;
  24. int u;
  25. while (head <= tail){
  26. u = q[head++];
  27. Redge(u) if (ed[k].f && vis[to = ed[k].to] != now){
  28. d[to] = d[u] + 1; vis[to] = now;
  29. if (to == T) return true;
  30. q[++tail] = to;
  31. }
  32. }
  33. return vis[T] == now;
  34. }
  35. int dfs(int u,int minf){
  36. if (u == T || !minf) return minf;
  37. int flow = 0,f,to;
  38. if (used[u] != now) cur[u] = h[u],used[u] = now;
  39. for (int& k = cur[u]; k; k = ed[k].nxt)
  40. if (d[to = ed[k].to] == d[u] + 1 && (f = dfs(to,min(minf,ed[k].f)))){
  41. ed[k].f -= f; ed[k ^ 1].f += f;
  42. flow += f; minf -= f;
  43. if (!minf) break;
  44. }
  45. return flow;
  46. }
  47. int maxflow(){
  48. int flow = 0; now = 1;
  49. while (bfs()){
  50. flow += dfs(S,INF);
  51. now++;
  52. }
  53. return flow;
  54. }
  55. int N,M,n;
  56. struct point{int x,y,w,c,id;}p[maxn];
  57. inline bool cmp1(const point& a,const point& b){
  58. return a.x == b.x ? a.y < b.y : a.x < b.x;
  59. }
  60. inline bool cmp2(const point& a,const point& b){
  61. return a.y == b.y ? a.x < b.x : a.y < b.y;
  62. }
  63. void solve(){
  64. int t;
  65. sort(p + 1,p + 1 + n,cmp1);
  66. REP(i,n){
  67. t = (p[i].y + 2 * (p[i].x & 1)) % 4;
  68. if (p[i + 1].x != p[i].x || p[i + 1].y != p[i].y + 1) continue;
  69. if (t == 0) p[i].c ? build(p[i].id,p[i + 1].id,INF) : build(p[i + 1].id,p[i].id,INF);
  70. if (t == 2) p[i].c ? build(p[i].id,p[i + 1].id,INF) : build(p[i + 1].id,p[i].id,INF);
  71. if (t == 3) !p[i].c ? build(p[i].id,p[i + 1].id,min(p[i].w,p[i + 1].w)) : build(p[i + 1].id,p[i].id,min(p[i].w,p[i + 1].w));
  72. }
  73. sort(p + 1,p + 1 + n,cmp2);
  74. REP(i,n){
  75. t = (p[i].y + 2 * (p[i].x & 1)) % 4;
  76. if (p[i + 1].y != p[i].y || p[i + 1].x != p[i].x + 1) continue;
  77. if (t == 0) p[i].c ? build(p[i].id,p[i + 1].id,INF) : build(p[i + 1].id,p[i].id,INF);
  78. if (t == 1) p[i].c ? build(p[i].id,p[i + 1].id,INF) : build(p[i + 1].id,p[i].id,INF);
  79. if (t == 2) p[i].c ? build(p[i].id,p[i + 1].id,INF) : build(p[i + 1].id,p[i].id,INF);
  80. if (t == 3) p[i].c ? build(p[i].id,p[i + 1].id,INF) : build(p[i + 1].id,p[i].id,INF);
  81. }
  82. printf("%d\n",maxflow());
  83. }
  84. int main(){
  85. N = read(); M = read(); n = read(); S = 0; T = n + 1;
  86. swap(N,M);
  87. int t;
  88. REP(i,n){
  89. p[i].id = i;
  90. p[i].x = read();
  91. p[i].y = read();
  92. swap(p[i].x,p[i].y);
  93. p[i].w = read();
  94. p[i].c = (p[i].x & 1) ^ (p[i].y & 1);
  95. t = (p[i].y + 2 * (p[i].x & 1)) % 4;
  96. if (t && t - 3) p[i].c ? build(S,i,p[i].w) : build(i,T,p[i].w);
  97. }
  98. solve();
  99. return 0;
  100. }

BZOJ4823 [Cqoi2017]老C的方块 【最小割】的更多相关文章

  1. bzoj4823: [Cqoi2017]老C的方块(最小割)

    4823: [Cqoi2017]老C的方块 题目:传送门 题解: 毒瘤题ORZ.... 太菜了看出来是最小割啥边都不会建...狂%大佬强强强   黑白染色?不!是四个色一起染,四层图跑最小割... 很 ...

  2. bzoj 4823: [Cqoi2017]老C的方块 [最小割]

    4823: [Cqoi2017]老C的方块 题意: 鬼畜方块游戏不解释... 有些特殊边,有些四个方块组成的图形,方块有代价,删掉一些方块使得没有图形,最小化代价. 比较明显的最小割,一个图形中必须删 ...

  3. BZOJ4823 CQOI2017老C的方块(最小割)

    如果将其转化为一个更一般的问题即二分图带权最小单边点覆盖(最小控制集)感觉是非常npc的.考虑原题给的一大堆东西究竟有什么奇怪的性质. 容易发现如果与特殊边相邻的两格子都放了方块,并且这两个格子都各有 ...

  4. [bzoj4823][Cqoi2017]老C的方块

    来自FallDream的博客,未经允许,请勿转载,谢谢. 挺有意思的一道题.... 看完题面比较明确是最小割,考虑怎么建图 想了比较久 突破口应该是题目中那张奇怪的图 观察这个奇怪的图和方块,很容易发 ...

  5. bzoj千题计划300:bzoj4823: [Cqoi2017]老C的方块

    http://www.lydsy.com/JudgeOnline/problem.php?id=4823 讨厌的形状就是四联通图 且左右各连一个方块 那么破坏所有满足条件的四联通就好了 按上图方式染色 ...

  6. bzoj 4823 & 洛谷 P3756 老C的方块 —— 最小割

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4823 https://www.luogu.org/problemnew/show/P3756 ...

  7. 【BZOJ4823】[CQOI2017]老C的方块(网络流)

    [BZOJ4823][CQOI2017]老C的方块(网络流) 题面 BZOJ 题解 首先还是给棋盘进行黑白染色,然后对于特殊边左右两侧的格子单独拎出来考虑. 为了和其他格子区分,我们把两侧的这两个格子 ...

  8. 【洛谷P3756】[CQOI2017]老C的方块(最小割)

    洛谷 题意: 给出一个网格图类似于这样: 现在给出一个\(n*m\)大小的网格,之后会给出一些点,若某些点相连形成了如下的几个图案,那么就是不好的. 现在可以删去一些点,但删除每个点都有一些代价,问最 ...

  9. BZOJ 4823 Luogu P3756 [CQOI2017]老C的方块 (网络流、最小割)

    题目链接 (Luogu) https://www.luogu.org/problem/P3756 (BZOJ) http://lydsy.com/JudgeOnline/problem.php?id= ...

随机推荐

  1. 阿里云服务器下安装LAMP环境(CentOS Linux 6.3)(1)

    阿里的云服务器准备好以后,我们首先要做的就是把自己购买的磁盘空间挂载到系统里面,我们为服务器选择的是 Linux 系统,确切说的是 CentOS 系统. 默认阿里云服务器带了一个 20G 的空间,一般 ...

  2. DOTA自走棋卡牌及搭配阵容

    这个游戏其实就根炉石jjc和A牌轮抽一样,前期要找着质量牌抓,保证你至少不漏.根据你的需求补一些你不会上场的阵容组件,最后根据你的组件和核心紫卡来哪张来决定打什么.另外也要考虑场上另外几家,如果有一家 ...

  3. Oracle 函数 之 wm_concat()

    wm_concat() 把列转换成一行一列显示,使用wm_concat函数可以显示在一行一列. --1 建表 create table province_city ( province varchar ...

  4. Vue 恢复初始值的快速方法

    vue 中经常定义很多data ,在用户进行一些操作后,需要讲data中的某个对象定义为初始值 例如 form: { title: '', describe: '', inspectionCatego ...

  5. Vuex的简单了解

    vuex的官网了解:https://vuex.vuejs.org/zh/guide/ 一.什么是vuex? Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式.它采用集中式存储管理应用的所 ...

  6. Tomcat:javax.management.InstanceNotFoundException: com.alibaba.druid:type=DruidDataSourceStat异常

    问题: 在关闭tomcat时: Tomat报出一下异常:ERROR [com.alibaba.druid.stat.DruidDataSourceStatManager] – unregister m ...

  7. Java 技术栈

    JAVA是一个面向对象的编程语言,由SUN公司的程序员所开发.它不仅吸收了C++的各种优点,而且还撇弃了C++中难以理解的概念,如多继承.指针等:因此JAVA语言具有功能强大且简单易用两个特征, JA ...

  8. tp5 修改自带success或error跳转模板页面

    tp5 修改自带success或error跳转模板页面 我们在使用tp5或者tp3.2的时候,用的成功或者失败跳转提示页面一般是用框架的.在后续开发过程中,根据实际项目需要,也是可以更改的,在此分享一 ...

  9. rpc - 接口返回数据结构的设计

    方案一: 系统级状态  .业务级别的状态同用 code要特殊声明保留状态,如若不声明保留状态,一旦业务开发人员用到了系统级的状态,就有必要侵入的改动业务返回的code(新code与业务欲返回的code ...

  10. day23-python之日志 re模块

    1.logging import logging #-----------------------------------logging.basicConfig logging.basicConfig ...