[BZOJ 2007] [Noi2010] 海拔 【平面图最小割(对偶图最短路)】
题目链接:BZOJ - 2007
题目分析
首先,左上角的高度是 0 ,右下角的高度是 1。那么所有点的高度一定要在 0 与 1 之间。然而选取 [0, 1] 的任何一个实数,都可以用整数 0 或 1 来替换,获得同样的效果。
虽然输出的答案要求是四舍五入到整数,但其实答案就是一个整数!
那么高度就一定是 0 或 1 了,并且还有一点,所有选 0 的点都连通,所有选 1 的点都联通。因为如果一个选 0 的点被选 1 的点包围,那么它选 1 更优。
于是整个图中所有的点分成了与左上角相连的集合 A ,与右下角相连的集合 B 。从集合 A 向 B 的边权会计入答案。这就是最小割模型。
这是一个规则的平面图,平面图最小割等于对偶图最短路。
建立对偶图:
1)增加一条从 S 到 T 的边,成为 ST 边。这条边把原图中外围无限大的平面部分分割成了一个有限部分 S’ 和无限部分 T’。S’ 与 T’ 就是对偶图的起点和终点。
2)将平面的每个部分看做一个虚拟点,每条边对应一条连接虚拟点的边。但是 ST 边不对应对偶图中的边。
对偶图的一条最短路就对应了原图的一个最小割。
原图的每一条单向边对应对偶图的边的方向可以画个图帮助确定。可以看看从 S’ 到 T’ 的路径中哪些方向的边计入最小割答案,也应是最短路答案。
写 dijkstra !卡 SPFA!
代码
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue> using namespace std; const int MaxN = 500 + 5, INF = 999999999; int n, S, T;
int Map[MaxN][MaxN][5], d[MaxN * MaxN]; bool Visit[MaxN * MaxN]; inline int Calc(int x, int y) {return (x - 1) * n + y;} struct Edge
{
int v, w;
Edge *Next;
} E[MaxN * MaxN * 4], *P = E, *Point[MaxN * MaxN]; inline void AddEdge(int x, int y, int z) {
++P; P -> v = y; P -> w = z;
P -> Next = Point[x]; Point[x] = P;
} struct ES
{
int x, y;
ES() {}
ES(int a, int b) {
x = a; y = b;
}
}; struct Cmp
{
bool operator () (ES e1, ES e2) {
return e1.y > e2.y;
}
}; priority_queue<ES, vector<ES>, Cmp> Q; int main()
{
scanf("%d", &n);
//Input data...
for (int i = 1; i <= n + 1; ++i)
for (int j = 1; j <= n; ++j)
scanf("%d", &Map[i][j][0]);
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= n + 1; ++j)
scanf("%d", &Map[i][j][1]);
for (int i = 1; i <= n + 1; ++i)
for (int j = 2; j <= n + 1; ++j)
scanf("%d", &Map[i][j][2]);
for (int i = 2; i <= n + 1; ++i)
for (int j = 1; j <= n + 1; ++j)
scanf("%d", &Map[i][j][3]);
//Input done...
S = n * n + 1; T = n * n + 2;
for (int i = 1; i <= n + 1; ++i) {
for (int j = 1; j <= n + 1; ++j) {
if (j <= n) {
if (i == 1) AddEdge(Calc(i, j), T, Map[i][j][0]);
else if (i == n + 1) AddEdge(S, Calc(i - 1, j), Map[i][j][0]);
else AddEdge(Calc(i, j), Calc(i - 1, j), Map[i][j][0]);
}
if (j > 1) {
if (i == 1) AddEdge(T, Calc(i, j - 1), Map[i][j][2]);
else if (i == n + 1) AddEdge(Calc(i - 1, j - 1), S, Map[i][j][2]);
else AddEdge(Calc(i - 1, j - 1), Calc(i, j - 1), Map[i][j][2]);
}
if (i <= n) {
if (j == 1) AddEdge(S, Calc(i, j), Map[i][j][1]);
else if (j == n + 1) AddEdge(Calc(i, j - 1), T, Map[i][j][1]);
else AddEdge(Calc(i, j - 1), Calc(i, j), Map[i][j][1]);
}
if (i > 1) {
if (j == 1) AddEdge(Calc(i - 1, j), S, Map[i][j][3]);
else if (j == n + 1) AddEdge(T, Calc(i - 1, j - 1), Map[i][j][3]);
else AddEdge(Calc(i - 1, j), Calc(i - 1, j - 1), Map[i][j][3]);
}
}
}
//Build_Edge done...
memset(Visit, 0, sizeof(Visit));
for (int i = 1; i <= T; ++i) d[i] = INF;
d[S] = 0;
while (!Q.empty()) Q.pop();
ES Now;
for (int i = 1; i <= T; ++i) Q.push(ES(i, d[i]));
while (!Q.empty()) {
Now = Q.top(); Q.pop();
if (Visit[Now.x]) continue;
if (Now.x == T) break;
Visit[Now.x] = true;
for (Edge *j = Point[Now.x]; j; j = j -> Next) {
if (d[Now.x] + j -> w < d[j -> v]) {
d[j -> v] = d[Now.x] + j -> w;
Q.push(ES(j -> v, d[j -> v]));
}
}
}
printf("%d\n", d[T]);
return 0;
}
[BZOJ 2007] [Noi2010] 海拔 【平面图最小割(对偶图最短路)】的更多相关文章
- bzoj 2007: [Noi2010]海拔【最小割+dijskstra】
上来就跑3e5的最大流--脑子抽了 很容易看出,每个地方的海拔都是0或1因为再高了没有意义,又,上去下来再上去没有意义,所以最后一定是从s连着一片0,剩下连着t一片1,然后有贡献的就是01交接的那些边 ...
- Vijos1734 NOI2010 海拔 平面图最小割
建立平面图的对偶图,把最小割转化成最短路问题 Dijkstra算法堆优化 (被输入顺序搞WA了好几次T_T) #include <cstdio> #include <cstring& ...
- bzoj2007/luoguP2046 海拔(平面图最小割转对偶图最短路)
bzoj2007/luoguP2046 海拔(平面图最小割转对偶图最短路) 题目描述: bzoj luogu 题解时间: 首先考虑海拔待定点的$h$都应该是多少 很明显它们都是$0$或$1$,并且所 ...
- 【BZOJ1001】狼抓兔子(平面图最小割转最短路)
题意:有一张平面图,求它的最小割.N,M.表示网格的大小,N,M均小于等于1000. 左上角点为(1,1),右下角点为(N,M).有以下三种类型的道路 1:(x,y)<==>(x+1,y ...
- BZOJ.2007.[NOI2010]海拔(最小割 对偶图最短路)
题目链接 想一下能猜出,最优解中海拔只有0和1,且海拔相同的点都在且只在1个连通块中. 这就是个平面图最小割.也可以转必须转对偶图最短路,不然只能T到90分了..边的方向看着定就行. 不能忽略回去的边 ...
- BZOJ 2007 海拔(平面图最小割转对偶图最短路)
首先注意到,把一个点的海拔定为>1的数是毫无意义的.实际上,可以转化为把这些点的海拔要么定为0,要么定为1. 其次,如果一个点周围的点的海拔没有和它相同的,那么这个点的海拔也是可以优化的,即把这 ...
- BZOJ2007/LG2046 「NOI2010」海拔 平面图最小割转对偶图最短路
问题描述 BZOJ2007 LG2046 题解 发现左上角海拔为 \(0\) ,右上角海拔为 \(1\) . 上坡要付出代价,下坡没有收益,所以有坡度的路越少越好. 所以海拔为 \(1\) 的点,和海 ...
- BZOJ 2007: [Noi2010]海拔
2007: [Noi2010]海拔 Time Limit: 20 Sec Memory Limit: 552 MBSubmit: 2410 Solved: 1142[Submit][Status] ...
- 洛谷P2046 [NOI2010]海拔(最小割,平面图转对偶图)
传送门 不明白为什么大佬们一眼就看出这是最小割…… 所以总而言之这就是一个最小割我也不知道为什么 然后边数太多直接跑会炸,所以要把平面图转对偶图,然后跑一个最短路即可 至于建图……请看代码我实在无能为 ...
随机推荐
- wind安装selenium
1.按win+r进入运行模式,然后输入cmd进入命令行 2.输入pip按回车 查看命令帮助 3.然后输入pip install selenium 按回车,然后等待 下载,下载好了会自动安装完成 3.然 ...
- CentOS6.5解决中文乱码与设置字符集
[ CleverCode发表在csdn博客中的原创作品,请勿转载,原创地址:http://blog.csdn.net/clevercode/article/details/46377577] 1)说明 ...
- Android之TextureView浅析
近期.在改动Android4.4的原生相机Camera2,非常习惯的去寻找SurfaceView.结果任凭我使用grep还是ack.都无法搜索到SurfaceView,最后还是通过代码CameraAc ...
- [转] npm 模块安装机制简介
npm 是 Node 的模块管理器,功能极其强大.它是 Node 获得成功的重要原因之一. 正因为有了npm,我们只要一行命令,就能安装别人写好的模块 . $ npm install 本文介绍 npm ...
- Bash算术计算
1:$(( )) 2:$[ ] 3:`expr $x + $y` 4:bc命令 #!/bin/bash x= y= echo $(( x + y )) echo $[ $x + $y ] echo ` ...
- Codeforces 231E - Cactus
231E - Cactus 给一个10^5个点的无向图,每个点最多属于一个环,规定两点之间的简单路:从起点到终点,经过的边不重复 给10^5个询问,每个询问两个点,问这两个点之间有多少条简单路. 挺综 ...
- JAVA学习笔记--二
一.抽象类: 访问修饰符 abstract class 类名{ } 抽象类和普通类的区别: 1. 抽象类不能被实例化 2. 抽象类一般含有抽象方法 抽象方法:在抽象类中只有方法签名(方法声明),没有方 ...
- 把Excel数据导入到数据库
引入命名空间 using System.IO; using System.Data; using System.Data.OleDb; 引入命名空间 首先要把Excel上传到服务器 //上传Excel ...
- iOS将产品进行多语言发布,开发
多语言就是程序的国际化.在Xcode中要实现程序的国际化,只需要简单配置,并修改相应的字符串键值对即可. 应用程序的国际化主要包括三个方面:A.程序名称国际化:B.程序内容国际化:C.程序资源国际化 ...
- iOS中常用的正则表达式
iOS常用正则表达式 正则表达式用于字符串处理.表单验证等场合,实用高效.现将一些常用的表达式收集于此,以备不时之需. 匹配中文字符的正则表达式: [\u4e00-\u9fa5]评注:匹配中文还真是个 ...