BZOJ 1001……

并不会这个trick,所以笔记要详细一点。

前置知识 : 平面图转对偶图    传送门

听说直接$Dinic$就好了,还跑得比正解快……

首先我们按照平面图的定义,把网格图中所有的平面以及另加的起点和终点在新图中标号,一共有$(n - 1) * (m - 1) * 2 + 2$个点,标完样例之后大概是这样子的:

然后我们接着按照定义,把有相邻的边的点连上双向边,对于那些在边界上的边,我们分别选择和$st$和$ed$连边,具体来说是这样的:

红色的边和$st$连边,蓝色的边和$ed$连边,其他黑色的边和它相邻的两个联通块连边。

注意$n == 1$或者$m == 1$的时候其实是一条链的情况,只要把最小的边鸽掉就好了,这时候所有的边都是要从$st$出发连到$ed$的,但是我的写法会挂掉,所以需要拎出来特判一下。

容易发现这样子构图之后从$st$到$ed$的每一条路都对应了原图中左上角到右下角的一个鸽,这样子我们求一个最小鸽就变成了一个最短路,就能方便地跑过去了。

要注意一个细节就是说$st$和$ed$必须放在左下角和右上角(可以对调),因为我们在原图中是要从左上角到右下角求一个最小鸽,要不然就不代表从左上角到右下角的一个最小鸽了吧。

连完边之后的效果图大概是这个大神博客里面的样子。    戳这里

时间复杂度$O(nmlognm)$。

Code:

#include <cstdio>
#include <cstring>
#include <queue>
#include <iostream>
using namespace std;
typedef pair <int, int> pin; const int N = 2e6 + ;
const int M = 6e6 + ; int n, m, tot = , head[N], dis[N];
bool vis[N]; struct Edge {
int to, nxt, val;
} e[M]; inline void add(int from, int to, int val) {
e[++tot].to = to;
e[tot].val = val;
e[tot].nxt = head[from];
head[from] = tot;
} inline void addEdge(int x, int y, int v) {
add(x, y, v), add(y, x, v);
} inline void read(int &X) {
X = ; char ch = ; int op = ;
for(; ch > '' || ch < ''; ch = getchar())
if(ch == '-') op = -;
for(; ch >= '' && ch <= ''; ch = getchar())
X = (X << ) + (X << ) + ch - ;
X *= op;
} priority_queue <pin> Q;
inline void dij(int st) {
memset(dis, 0x3f, sizeof(dis));
memset(vis, , sizeof(vis));
Q.push(pin(dis[st] = , st));
for(; !Q.empty(); ) {
int x = Q.top().second; Q.pop();
if(vis[x]) continue;
vis[x] = ;
for(int i = head[x]; i; i = e[i].nxt) {
int y = e[i].to;
if(dis[y] > dis[x] + e[i].val) {
dis[y] = dis[x] + e[i].val;
Q.push(pin(-dis[y], y));
}
}
}
} int main() {
// freopen("5.in", "r", stdin); read(n), read(m);
int st = (n - ) * (m - ) * + , ed = st + ;
if(n == || m == ) {
for(int i = ; i <= n; i++)
for(int j = ; j < m; j++) {
int val; read(val);
addEdge(st, ed, val);
}
for(int i = ; i < n; i++)
for(int j = ; j <= m; j++) {
int val; read(val);
addEdge(st, ed, val);
}
for(int i = ; i < n; i++)
for(int j = ; j < m; j++) {
int val; read(val);
addEdge(st, ed, val);
}
} else {
for(int i = ; i <= n; i++)
for(int j = ; j < m; j++) {
int val; read(val);
if(i == ) addEdge(ed, * ((i - ) * (m - ) + j), val);
if(i == n) addEdge(st, * ((i - ) * (m - ) + j) - , val);
if(i != && i != n) addEdge( * ((i - ) * (m - ) + j), * ((i - ) * (m - ) + j) - , val);
}
for(int i = ; i < n; i++)
for(int j = ; j <= m; j++) {
int val; read(val);
if(j == ) addEdge(st, * ((i - ) * (m - ) + j) - , val);
if(j == m) addEdge(ed, * ((i - ) * (m - ) + j - ), val);
if(j != && j != m) addEdge( * ((i - ) * (m - ) + j) - , * ((i - ) * (m - ) + j) - , val);
}
for(int i = ; i < n; i++)
for(int j = ; j < m; j++) {
int val; read(val);
addEdge( * ((i - ) * (m - ) + j) - , * ((i - ) * (m - ) + j), val);
}
} dij(st); printf("%d\n", dis[ed]);
return ;
}

Luogu 4001 [BJOI2006]狼抓兔子的更多相关文章

  1. BZOJ1001 洛谷4001 [BJOI2006]狼抓兔子 题解

    题目 这个题目有多种解法,这个题也是一个比较经典的题了,正是因为他的多样的做法,这个题主要难在建图和优化,因为这是一个网格图,所以spfa肯定过不去,所以用最短路解法的话,只能用dij,而网络流也是要 ...

  2. BZOJ1001或洛谷4001 [BJOI2006]狼抓兔子

    BZOJ原题链接 洛谷原题链接 显然就是求最小割. 而对于一个平面图有结论,最大流=最小割=对偶图最短路. 所以这题可用最大流或是转换为对偶图求最短路,这里我是用的对偶图. 虽然理论上按上界算,这题\ ...

  3. P4001 [BJOI2006]狼抓兔子(对偶图)

    P4001 [BJOI2006]狼抓兔子 最短路+对偶图 看这题最容易想到的就是网络流.Dinic可以过,据说还跑得比正解快. 如果不写网络流,那么需要知道2个前置知识:平面图和对偶图(右转baidu ...

  4. BJOI2006狼抓兔子

    1001: [BeiJing2006]狼抓兔子 Time Limit: 15 Sec  Memory Limit: 162 MBSubmit: 9967  Solved: 2267[Submit][S ...

  5. 752. [BJOI2006] 狼抓兔子

    ★★★   输入文件:bjrabbit.in   输出文件:bjrabbit.out   简单对比时间限制:1 s   内存限制:162 MB Description   Source: Beijin ...

  6. [BJOI2006]狼抓兔子

    题目描述 现在小朋友们最喜欢的"喜羊羊与灰太狼",话说灰太狼抓羊不到,但抓兔子还是比较在行的,而且现在的兔子还比较笨,它们只有两个窝,现在你做为狼王,面对下面这样一个网格的地形: ...

  7. 1001. [BJOI2006]狼抓兔子【最小割】

    Description 现在小朋友们最喜欢的"喜羊羊与灰太狼",话说灰太狼抓羊不到,但抓兔子还是比较在行的, 而且现在的兔子还比较笨,它们只有两个窝,现在你做为狼王,面对下面这样一 ...

  8. BZOJ1001 BJOI2006 狼抓兔子

    Description 现在小朋友们最喜欢的"喜羊羊与灰太狼",话说灰太狼抓羊不到,但抓兔子还是比较在行的,而且现在的兔子还比较笨,它们只有两个窝,现在你做为狼王,面对下面这样一个 ...

  9. [BJOI2006]狼抓兔子(网络流)

    题目描述 现在小朋友们最喜欢的"喜羊羊与灰太狼",话说灰太狼抓羊不到,但抓兔子还是比较在行的,而且现在的兔子还比较笨,它们只有两个窝,现在你做为狼王,面对下面这样一个网格的地形: ...

随机推荐

  1. uva120 Stacks of Flapjacks (构造法)

    这个题没什么算法,就是想出怎么把答案构造出来就行. 思路:越大的越放在底端,那么每次就找出还没搞定的最大的,把它移到当前还没定好的那些位置的最底端,定好的就不用管了. 这道题要处理好输入,每次输入的一 ...

  2. C#面向对象(三):多态

    前文链接: C#面向对象(一):明确几个简单的概念作为开胃菜 C#面向对象(二):封装和继承 今天来聊聊面向对象的多态,这部分算是比较重要和核心的,很多工作2年多的程序员其实对于面向对象和多态的理解也 ...

  3. php redis 操作手册

    String 类型操作 string是redis最基本的类型,而且string类型是二进制安全的.意思是redis的string可以包含任何数据.比如jpg图片或者序列化的对象 1 $redis-&g ...

  4. java 简单实现socket

    server端 package socket; import java.io.BufferedReader; import java.io.IOException; import java.io.In ...

  5. 微信小程序 报错Setting data field "variableName" to undefined is invalid.

    Setting data field "variableName" to undefined is invalid. 将数据字段“variableName”设置为未定义是无效的. ...

  6. wpf中为DataGrid添加checkbox支持多选全选

    项目中用到DataGrid, 需要在第一列添加checkbox, 可以多选.全选. 其中涉及的概念DataTemplate, DataGridCellStyle, DataGridCellContro ...

  7. webrtc自带client的音频引擎创建代码走读

    src\webrtc\examples\peerconnection\client\conductor.cc1.bool Conductor::InitializePeerConnection()1. ...

  8. Spring Boot Starter 速查

    Spring Boot应用启动器基本的一共有40多种,常用的如下 1)spring-boot-starter 这是Spring Boot的核心启动器,包含了自动配置.日志和YAML. 2)spring ...

  9. Java基础--比较器Comparator

    Comparable接口和Comparator接口都是用来定义集合中的排序的,只是Comparable是在集合内部定义排序的实现,Comparator是在集合外部排序的实现. Comparable 的 ...

  10. Java基础--HashCode

    如果一个类的对象要用做hashMap的key,那么一定要注意覆盖该类的equals和hashCode方法. equals()是基类Object的方法,用于判断对象是否有相同地址及是否为同一对象 pub ...