@description@

给出一个N*M的网格图,有一些方格里面存在城市,其中首都位于网格图的左上角。

你可以沿着网络的边界走,要求你走的路线是一个环并且所有城市都要被你走出来的环圈起来,即想从方格图的外面走到任意一个城市一定要和你走的路线相交。

你沿着方格的边界走是需要费用的,不同的边界费用可能不同,求最小代价。

1<=N,M<=400,走过边界的代价为正整数且不超过10^9

Sample Input

3 3

1 0 1

0 0 0

0 1 0

2 1 1 3

5 6 1 1

2 1 1 3

2 1 1

3 4 1

4 1 1

5 1 2

Sample Output

22

HINT

@solution@

人类智慧题。

首先路径可能重复经过边或者点这件事很难描述,而且本身很不自然。

我们将走过一条边看成两种,一种从左/上侧经过,一种从右/下侧经过(竖着的边就是左右侧,横着的边就是上下侧)。

比如下图就是转变后的例子:

这样就不会经过重边重点,而且可以很自然地描述包含一条边/一个格点的概念。

假如没有额外限制,就只是找一个简单最小环(并且一定包含左上角,因为左上角一定有一个城市)。

如果左上角的格点为 (0, 0),那么跑一个从 (0, 1) 到 (1, 0) 的最短路即可。

但是我怎么表达包含一个城市的概念。

假如只有左上角有城市,则只要确定起点为 (0, 1) 终点为 (1, 0) 就可以包含左上角的城市了。

假如城市与城市之间有些割不断的联系,那么我跑最短路时不横断这些联系,既然我已经包含了左上角,就可以保证所有城市都在最小环里面了。

有一个结论:左上角的格点到城市的左上角的最短路一定会被包含其中

直观地理解:

假如蓝色是一种方案,绿色是最短路。当我把黄色区域加入进去过后,因为是最短路,所以方案一定不会变差(否则绿色就不是最短路了)。

即我们总可以用最短路代替边界。

那么建出最短路树,只要不横断这些树边就一定合法了。

具体实现,我们将一个格点拆成四个,建出一个类似于如下的图:

拆出来的四个点之间,如果不会横断最短路就连边权为 0 的边。

同时需要注意,一个城市四个角对应的点不向其他点连边。

左上角的格点拆出来的对应左上角的那个点不连边,跑左上角的格点对应的右上角到左上角的格点对应左下角的那个点的最短路。

两个相邻格点之间也要连,边权即原图中边的边权。

@accepted code@

#include<cstdio>
#include<queue>
#include<algorithm>
using namespace std;
#define rep(G, x) for(Graph::edge *p = G.adj[x];p;p = p->nxt)
typedef long long ll;
const int MAXN = 400 + 5;
const int MAXV = 4*MAXN*MAXN;
const int MAXE = 16*MAXV + 5;
const ll INF = (1LL<<60);
struct Graph{
struct edge{
int to, dis;
edge *nxt;
}edges[MAXE + 5], *adj[MAXV + 5], *ecnt;
Graph() {ecnt = edges;}
void addedge(int u, int v, int w) {
edge *p = (++ecnt);
p->to = v, p->dis = w, p->nxt = adj[u], adj[u] = p;
p = (++ecnt);
p->to = u, p->dis = w, p->nxt = adj[v], adj[v] = p;
// printf("! %d %d %d\n", u, v, w);
}
void clear(int n) {
ecnt = edges;
for(int i=1;i<=n;i++)
adj[i] = NULL;
}
}G;
int hp[MAXV + 5], pre[MAXV + 5];
ll f[MAXV + 5], dis[MAXV + 5];
void update(int x, ll k, const int &n) {
f[x] = k;
while( x ) {
hp[x] = x;
if( (x<<1) <= n && f[hp[x<<1]] < f[hp[x]] )
hp[x] = hp[x<<1];
if( (x<<1|1) <= n && f[hp[x<<1|1]] < f[hp[x]] )
hp[x] = hp[x<<1|1];
x >>= 1;
}
}
void dijkstra(int s, const int &n) {
for(int i=1;i<=n;i++)
dis[i] = f[i] = INF, hp[i] = i;
update(s, dis[s] = 0, n);
while( f[hp[1]] != INF ) {
int x = hp[1]; update(x, INF, n);
rep(G, x) {
if( dis[x] + p->dis < dis[p->to] ) {
update(p->to, dis[p->to] = dis[x] + p->dis, n);
pre[p->to] = x;
}
}
}
}
int id[MAXN + 5][MAXN + 5], cnt;
int A[MAXN + 5][MAXN + 5], B[MAXN + 5][MAXN + 5], C[MAXN + 5][MAXN + 5];
bool tg[MAXV + 5];
queue<int>que;
int ind(int x, int p) {
return (x - 1) * 4 + p;
}
bool check(int x, int y) {
return (pre[x] == y && tg[x]) || (pre[y] == x && tg[y]);
}
int main() {
int N, M; scanf("%d%d", &N, &M);
for(int i=1;i<=N;i++)
for(int j=1;j<=M;j++)
scanf("%d", &A[i][j]);
for(int i=1;i<=N+1;i++)
for(int j=1;j<=M+1;j++)
id[i][j] = (++cnt);
for(int i=1;i<=N;i++)
for(int j=1;j<=M+1;j++) {
scanf("%d", &B[i][j]);
G.addedge(id[i][j], id[i+1][j], B[i][j]);
}
for(int i=1;i<=N+1;i++)
for(int j=1;j<=M;j++) {
scanf("%d", &C[i][j]);
G.addedge(id[i][j], id[i][j+1], C[i][j]);
}
dijkstra(1, cnt);
for(int i=1;i<=N;i++)
for(int j=1;j<=M;j++)
if( A[i][j] ) que.push(id[i][j]), tg[id[i][j]] = true;
while( !que.empty() ) {
int f = que.front(); que.pop();
if( !tg[pre[f]] )
que.push(pre[f]), tg[pre[f]] = true;
}
G.clear(cnt);
for(int i=1;i<=N;i++)
for(int j=1;j<=M+1;j++) {
if( !A[i][j-1] )
G.addedge(ind(id[i][j], 3), ind(id[i+1][j], 2), B[i][j]);
if( !A[i][j] )
G.addedge(ind(id[i][j], 4), ind(id[i+1][j], 1), B[i][j]);
}
for(int i=1;i<=N+1;i++)
for(int j=1;j<=M;j++) {
if( !A[i-1][j] )
G.addedge(ind(id[i][j], 1), ind(id[i][j+1], 2), C[i][j]);
if( !A[i][j] )
G.addedge(ind(id[i][j], 4), ind(id[i][j+1], 3), C[i][j]);
}
for(int i=1;i<=N+1;i++)
for(int j=1;j<=M+1;j++) {
if( i == 1 && j == 1 ) continue;
if( !(check(id[i][j], id[i-1][j]) || A[i-1][j] || A[i-1][j-1]) )
G.addedge(ind(id[i][j], 1), ind(id[i][j], 2), 0);
if( !(check(id[i][j], id[i][j-1]) || A[i][j-1] || A[i-1][j-1]) )
G.addedge(ind(id[i][j], 2), ind(id[i][j], 3), 0);
if( !(check(id[i][j], id[i+1][j]) || A[i][j-1] || A[i][j]) )
G.addedge(ind(id[i][j], 3), ind(id[i][j], 4), 0);
if( !(check(id[i][j], id[i][j+1]) || A[i-1][j] || A[i][j]) )
G.addedge(ind(id[i][j], 4), ind(id[i][j], 1), 0);
}
dijkstra(ind(1, 1), ind(cnt, 4));
printf("%lld\n", dis[ind(1, 3)]);
}

@details@

只用了 N 没有用 M 这个变量的人一定不止我一个人吧。

所以 2014 年出的题我现在还是不会。

@bzoj - 4356@ Ceoi2014 Wall的更多相关文章

  1. BZOJ4356 : Ceoi2014 Wall

    求出左上角到每个需要保护的点左上角的最短路树,那么最优解一定圈住了它们. 然后将每个点拆成四个点,四个点之间如果没跨越最短路树的树边,那就连0权边. 每个需要保护的点四周4个点都不可通行,求出最短路即 ...

  2. bzoj AC倒序

    Search GO 说明:输入题号直接进入相应题目,如需搜索含数字的题目,请在关键词前加单引号 Problem ID Title Source AC Submit Y 1000 A+B Problem ...

  3. BZOJ 1665: [Usaco2006 Open]The Climbing Wall 攀岩

    题目 1665: [Usaco2006 Open]The Climbing Wall 攀岩 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 197  Sol ...

  4. 【BZOJ】1665: [Usaco2006 Open]The Climbing Wall 攀岩(spfa)

    http://www.lydsy.com/JudgeOnline/problem.php?id=1665 这题只要注意到“所有的落脚点至少相距300”就可以大胆的暴力了. 对于每个点,我们枚举比他的x ...

  5. BZOJ 1113 Wall ——计算几何

    凸包第一题. 自己认为自己写的是Andrew 其实就是xjb写出来居然过掉了测试. 刚开始把pi定义成了int,调了半天 #include <map> #include <cmath ...

  6. 【BZOJ】【2120】数颜色 & 【2453】维护队列

    莫队算法 分块大法吼 这题乍一看跟HH的项链很像啊……只是多了一个修改操作……然而我就不会做了

  7. [Usaco2006 Open]The Climbing Wall 攀岩

    Description One of the most popular attractions at the county fair is the climbing wall. Bessie want ...

  8. BZOJ 2127: happiness [最小割]

    2127: happiness Time Limit: 51 Sec  Memory Limit: 259 MBSubmit: 1815  Solved: 878[Submit][Status][Di ...

  9. [poj1113][Wall] (水平序+graham算法 求凸包)

    Description Once upon a time there was a greedy King who ordered his chief Architect to build a wall ...

随机推荐

  1. SpringBoot-(10)配置虚拟路径-指定外部路径文件夹存取文件

    参考:https://blog.csdn.net/feng2147685/article/details/95623135 package com.online.director; import or ...

  2. mysql导入数据中文乱码解决方法

    常见的MySQL导入方法有两种 第一种方法,使用MySQL命令导入 mysql -uroot -p123456 --default-character-set=utf8 [db_name] < ...

  3. Vue2.0史上最全入坑教程(中)—— 脚手架代码详解

    书接上文我们说道,如何利用脚手架(vue-cli)构建一个vue项目,本回书我们一起来学习分析下代码. 回顾下创建后的项目目录:   说明:在*.vue文件,template标签里写html代码,且t ...

  4. Javascript-正则表达式常用验证

    <div> <h1>一.判断中国邮政编码匹配</h1> <p>分析:中国邮政编码都是6位,且为纯数字</p> <div>邮政编码 ...

  5. 模拟4题解 T1礼物

    T1 题目描述 夏川的生日就要到了.作为夏川形式上的男朋友,季堂打算给夏川买一些生 日礼物. 商店里一共有种礼物.夏川每得到一种礼物,就会获得相应喜悦值Wi(每种 礼物的喜悦值不能重复获得). 每次, ...

  6. web前端学习(二)html学习笔记部分(7)--web存储2

    1.2.20  web存储 1.2.20.1  Web存储-客户端存储数据新方法 1.两种方式 1)localStorage - 没有时间限制的数据存储 2)针对一个sessionStorage - ...

  7. The method getTextContent() is undefined ?

    晚上下班的时候,把班上写了半截的代码带了回来.结果回到家后出乎意料的是回来的时候将代码导入eclipse后,下面这行代码就直接报错了,显示 getTextContent()未定义 . ((Elemen ...

  8. 学习笔记(1)---matlab中常见函数解析

    一.fscanf函数 matlab中函数fscanf在文件读取方面的实例如下: 从文件中有格式地读数据 fscanf 语法1:[a,count]=fscanf(fid,format,size) 根据指 ...

  9. DX9纹理半像素偏移-Directly Mapping Texels to Pixels

    原文:DX9纹理半像素偏移-Directly Mapping Texels to Pixels 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/u01 ...

  10. python csv文件打开错误:_csv.Error: line contains NULL byte

    当python读取文件出现_csv.Error: line contains NULL byte时, # -*- coding:utf-8 -*- import csv with open(r'E:\ ...