【题解】CQOI2017老C的方块
网络流真的是一种神奇的算法。在一张图上面求感觉高度自动化的方案一般而言好像都是网络流的主阵地。讲真一开始看到这道题也有点懵,题面很长,感觉很难的样子。不过,仔细阅读了题意之后明白了:我们所要做的就是要用最小的代价,使得最后的图中不能出现给定的四种图案。
实际上之前做过一道非常毒瘤的网络流题目【无限之环】。当时就思考了一下:为什么出题人规定不能旋转直线管子?原因就是因为这样的图建不出来,它与不具有其他的管子的特点。那么可以断定:给出的这四个图案必然也是非常特殊的图形,否则不会只有这四个/不会是这四个。于是观察这四个图案,不难发现它们的特征:以一对中间夹了特殊边的方块为中心,分别有另一方块随意连接在上方。
我们从这个中心开始入手:由于要求最小值,所以-->最小割 / 费用流。但一个直观的感觉,它是在很多的方案当中做出选择,与最小割是比较贴合的。(每一种图案牵扯到四个方块,拿掉任何一个就可以破坏这个图形)如果每一种方案彼此平行,只需建出图暴力跑即可。可是会有交叉:当我们删去一个方块时,可能同时破坏了两个方案。
观察图案,由于上下,左右交错,一个中心只可能出现在一个方案中,但其两侧的方块却可能出现在不同的方案当中。于是我们对于这样两侧的方块进行黑白染色,保证每一种方案当中所牵涉到的另两个方块分别属于不同的颜色(由于题目的特殊性质是可以做到的)。
那么建边的方式也十分的自然了:
源点-->所有白色的点,边权为代价;所有白色的点-->中心连边,边权为INF;所有的中心 = 两条边 = 边权为各个方块的代价。所有的中心 --> 黑点,黑点 --> 汇点,边权为代价。此时的最小割所代表的意义即为我们做出的最小代价方案选择。
做出这题还是比较开心的,代码跑得也很快。不过细节比较多,要注意一下……
// luogu-judger-enable-o2
#include <bits/stdc++.h>
using namespace std;
#define maxn 300000
#define maxm 800000
#define ll long long
#define INF 9999999
int C, R, n, S, T, tot;
int Color[maxn], cnt;
int cnp = , head[maxn], cur[maxn];
int lev[maxn];
map <int, int> Map;
int dx[] = {, , , , , , -, -, -, -};
int dy[] = {-, , , , -, , -, , , }; struct edge
{
int to, last, f;
}E[maxm]; struct node
{
int x, y, w;
}P[maxn]; bool cmp(node a, node b)
{
if(a.x != b.x) return a.x < b.x;
return a.y < b.y;
} int read()
{
int x = , k = ;
char c;
c = getchar();
while(c < '' || c > '') { if(c == '-') k = -; c = getchar(); }
while(c >= '' && c <= '') x = x * + c - '', c = getchar();
return x * k;
} void add(int u, int v, int f)
{
E[cnp].to = v, E[cnp].f = f, E[cnp].last = head[u], head[u] = cnp ++;
E[cnp].to = u, E[cnp].f = , E[cnp].last = head[v], head[v] = cnp ++;
} bool Bfs()
{
queue <int> q;
memset(lev, , sizeof(lev));
q.push(S); lev[S] = ;
while(!q.empty())
{
int u = q.front(); q.pop();
for(int i = head[u]; i; i = E[i].last)
{
int v = E[i].to;
if(!lev[v] && E[i].f)
{
lev[v] = lev[u] + ;
q.push(v);
}
}
if(lev[T]) return ;
}
return ;
} int Dfs(int u, int nf)
{
if(u == T) return nf;
int lf = ;
for(int i = cur[u]; i; i = E[i].last)
{
int v = E[i].to;
if(lev[v] == lev[u] + && E[i].f)
{
int af = Dfs(v, min(E[i].f, nf));
nf -= af, lf += af;
E[i].f -= af, E[i ^ ].f += af;
if(!nf) return lf;
cur[u] = i;
}
}
if(!lf) lev[u] = -;
return lf;
} int Dinic()
{
int ans = ;
while(Bfs())
{
memcpy(cur, head, sizeof(head));
ans += Dfs(S, INF);
}
return ans;
} int id(int x, int y)
{
ll k = 1ll * R * (x - ) + 1ll * y;
if(Map[k]) return Map[k];
else return Map[k] = ++ tot;
} int Check(int x, int y)
{
ll k = 1ll * R * (x - ) + 1ll * y;
if(Map[k]) return Map[k];
else return ;
} void Get_Graph(int p)
{
int a = ++ tot, b = ++ tot, c = ++ tot;
add(a, b, P[p].w); add(b, c, P[p + ].w);
for(int i = ; i < ; i ++)
{
int xx = P[p].x + dx[i], yy = P[p].y + dy[i], tem;
if(xx < || xx > C || yy < || yy > R) continue;
if(tem = Check(xx, yy))
{
if(Color[tem] == ) add(tem, a, INF);
else add(c, tem, INF);
}
}
} int main()
{
C = read(), R = read();
swap(C, R); n = read();
S = , T = * n + ;
for(int i = ; i <= n; i ++)
{
int x = read(), y = read(), w = read();
swap(x, y);
if((x & ) && ((!((y - ) % )) || (!((y - ) % ))))
{
P[++ cnt].x = x, P[cnt].y = y;
P[cnt].w = w; continue;
}
if((!(x & )) && ((!((y - ) % )) || (!((y - ) % ))))
{
P[++ cnt].x = x, P[cnt].y = y;
P[cnt].w = w; continue;
}
if(x & )
{
if(((y - ) % )) add(S, id(x, y), w), Color[id(x, y)] = ;
else add(id(x, y), T, w), Color[id(x, y)] = ;
}
else
{
if(!((y - ) % )) add(id(x, y), T, w), Color[id(x, y)] = ;
else add(S, id(x, y), w), Color[id(x, y)] = ;
}
}
sort(P + , P + + cnt, cmp);
for(int i = ; i <= cnt; i += )
{
if(P[i + ].x != P[i].x) continue;
if(P[i + ].y != P[i].y + ) continue;
Get_Graph(i);
}
printf("%d\n", Dinic());
return ;
}
【题解】CQOI2017老C的方块的更多相关文章
- bzoj4823: [Cqoi2017]老C的方块(最小割)
4823: [Cqoi2017]老C的方块 题目:传送门 题解: 毒瘤题ORZ.... 太菜了看出来是最小割啥边都不会建...狂%大佬强强强 黑白染色?不!是四个色一起染,四层图跑最小割... 很 ...
- 【BZOJ4823】[CQOI2017]老C的方块(网络流)
[BZOJ4823][CQOI2017]老C的方块(网络流) 题面 BZOJ 题解 首先还是给棋盘进行黑白染色,然后对于特殊边左右两侧的格子单独拎出来考虑. 为了和其他格子区分,我们把两侧的这两个格子 ...
- bzoj 4823: [Cqoi2017]老C的方块 [最小割]
4823: [Cqoi2017]老C的方块 题意: 鬼畜方块游戏不解释... 有些特殊边,有些四个方块组成的图形,方块有代价,删掉一些方块使得没有图形,最小化代价. 比较明显的最小割,一个图形中必须删 ...
- BZOJ4823 [Cqoi2017]老C的方块 【最小割】
题目 老C是个程序员. 作为一个懒惰的程序员,老C经常在电脑上玩方块游戏消磨时间.游戏被限定在一个由小方格排成的R行C列网格上,如果两个小方格有公共的边,就称它们是相邻的,而且有些相邻的小方格之间的公 ...
- [bzoj4823][洛谷P3756][Cqoi2017]老C的方块
Description 老 C 是个程序员. 作为一个懒惰的程序员,老 C 经常在电脑上玩方块游戏消磨时间.游戏被限定在一个由小方格排成的R行C列网格上 ,如果两个小方格有公共的边,就称它们是相邻的, ...
- [CQOI2017]老C的方块 网络流
---题面--- 题解: 做这题做了好久,,,换了4种建图QAQ 首先我们观察弃疗的形状,可以发现有一个特点,那就是都以一个固定不变的特殊边为中心的,如果我们将特殊边两边的方块分别称为s块和t块, 那 ...
- [bzoj4823][Cqoi2017]老C的方块
来自FallDream的博客,未经允许,请勿转载,谢谢. 挺有意思的一道题.... 看完题面比较明确是最小割,考虑怎么建图 想了比较久 突破口应该是题目中那张奇怪的图 观察这个奇怪的图和方块,很容易发 ...
- [CQOI2017]老C的方块
题目描述 https://www.lydsy.com/JudgeOnline/problem.php?id=4823 题解 观察那四种条件 有没有什么特点? 我们可以把蓝线两边的部分看做两个区域,这样 ...
- bzoj千题计划300:bzoj4823: [Cqoi2017]老C的方块
http://www.lydsy.com/JudgeOnline/problem.php?id=4823 讨厌的形状就是四联通图 且左右各连一个方块 那么破坏所有满足条件的四联通就好了 按上图方式染色 ...
随机推荐
- 富文本编辑器 wangEditor.js
1.引用 wangEditor 相关js 和 css 下载地址:https://files.cnblogs.com/files/kitty-blog/WangEditor.zip 3.页面: < ...
- sencha inspector(调试工具)
Sencha Inspector 一:安装sencha inspector 使用Sencha Inspector下载Ext JS试用版(可在此处获得). 下载后,双击下载的文件以启动安装程序,然后按照 ...
- 吐血分享:QQ群霸屏技术教程2017(效益篇)
懂得如何做群排名了,接下来就要实质性的考虑产出了. 可能,咱们经常发现,一些群里拉人的,进群看某片,5元钱终生,这类是灰色的.其实正规的付费空间也很大. 群利润空间 有工作,有产品,有项目,可以做群排 ...
- Laravel POST请求API接口 使用validate表单验证返回欢迎页
突然遇到的问题 就是使用Laravel进行开发API接口的时候 发现在表单验证不通过的时候返回了登录页 猜测问题应该是因为表单验证失败后进行了重定向导致的 因为返回状态码200 网上找了好久没找到 ...
- mysql在cmd里中文乱码解决办法
右边画红线部分中文已经乱码,左边红线里中文则完美显示出来了. 解决办法 用set names utf-8: 效果如图
- java应用:csv文件的读写
csv数据特点: csv是文本格式,一行数据是一条记录,每个单元之间用“,”隔开.csv数据可以用Excel打开. 读写csv文件的主要程序如下所示: import java.io.BufferedR ...
- javaweb 项目部署到tomcat
1.准备环境 1.安装 mysql 2.安装java 环境 3.使用idea打war包 点击 apply 生成war包 将war包传到tomcat的webapp目录下,进入tomcat安装目录,进入b ...
- Apache Tomcat 整合
Infi-chu: http://www.cnblogs.com/Infi-chu/ 一.Apache+Tomcat整合是什么: 1.Apache默认访问端口是80,Tomcat默认访问端口是8080 ...
- BZOJ:2038: [2009国家集训队]小Z的袜子(hose)(莫队算法模板)
题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=2038 解题心得: 第一次接触莫队算法,很神奇,很巧妙.莫队算法主要就是用来解决多次询问时 ...
- C#读写txt文件的两种方法介绍 v
C#读写txt文件的两种方法介绍 1.添加命名空间 System.IO; System.Text; 2.文件的读取 (1).使用FileStream类进行文件的读取,并将它转换成char数组,然后输出 ...