BZOJ 1001 - 狼抓兔子 - [Dinic最大流][对偶图最短路]
题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1001
Description
现在小朋友们最喜欢的"喜羊羊与灰太狼",话说灰太狼抓羊不到,但抓兔子还是比较在行的,
而且现在的兔子还比较笨,它们只有两个窝,现在你做为狼王,面对下面这样一个网格的地形:
左上角点为(1,1),右下角点为(N,M)(上图中N=4,M=5).有以下三种类型的道路
1:(x,y)<==>(x+1,y)
2:(x,y)<==>(x,y+1)
3:(x,y)<==>(x+1,y+1)
道路上的权值表示这条路上最多能够通过的兔子数,道路是无向的. 左上角和右下角为兔子的两个窝,
开始时所有的兔子都聚集在左上角(1,1)的窝里,现在它们要跑到右下解(N,M)的窝中去,狼王开始伏击
这些兔子.当然为了保险起见,如果一条道路上最多通过的兔子数为K,狼王需要安排同样数量的K只狼,
才能完全封锁这条道路,你需要帮助狼王安排一个伏击方案,使得在将兔子一网打尽的前提下,参与的
狼的数量要最小。因为狼还要去找喜羊羊麻烦.
Input
第一行为N,M.表示网格的大小,N,M均小于等于1000.
接下来分三部分
第一部分共N行,每行M-1个数,表示横向道路的权值.
第二部分共N-1行,每行M个数,表示纵向道路的权值.
第三部分共N-1行,每行M-1个数,表示斜向道路的权值.
输入文件保证不超过10M
Output
输出一个整数,表示参与伏击的狼的最小数量.
Sample Input
3 4
5 6 4
4 3 1
7 5 3
5 6 7 8
8 7 6 5
5 5 5
6 6 6
Sample Output
14
HINT
2015.4.16新加数据一组,可能会卡掉从前可以过的程序。
题解:
无向边转成正反两条有向边,上Dinic求最大流。
vector存图会MLE,改用链式前向星就好了。
AC代码:
#include<bits/stdc++.h>
#define idx(i,j) ((i-1)*m+j)
using namespace std;
const int INF=0x3f3f3f3f;
const int maxn=*+;
const int maxm=*maxn; int n,m,w; struct Edge{
int u,v,c,f;
int next;
};
struct Dinic
{
int s,t; //源点汇点
Edge E[maxm];
int head[maxn],ne;
void init()
{
ne=;
memset(head,,sizeof(head));
}
void addedge(int u,int v,int c)
{
++ne;
E[ne].u=u, E[ne].v=v, E[ne].c=c, E[ne].f=;
E[ne].next=head[u];
head[u]=ne;
}
int dist[maxn],vis[maxn];
queue<int> q;
bool bfs() //在残量网络上构造分层图
{
memset(vis,,sizeof(vis));
while(!q.empty()) q.pop();
q.push(s);
dist[s]=;
vis[s]=;
while(!q.empty())
{
int now=q.front(); q.pop();
for(int i=head[now];i;i=E[i].next)
{
Edge& e=E[i]; int nxt=e.v;
if(!vis[nxt] && e.c>e.f)
{
dist[nxt]=dist[now]+;
q.push(nxt);
vis[nxt]=;
}
}
}
return vis[t];
}
int dfs(int now,int flow)
{
if(now==t || flow==) return flow;
int rest=flow,k;
for(int i=head[now];rest> && i;i=E[i].next)
{
Edge &e=E[i]; int nxt=e.v;
if(e.c>e.f && dist[nxt]==dist[now]+)
{
k=dfs(nxt,min(rest,e.c-e.f));
if(!k) dist[nxt]=; //剪枝,去掉增广完毕的点
e.f+=k; E[i^].f-=k;
rest-=k;
}
}
return flow-rest;
}
int mf; //存储最大流
int maxflow()
{
mf=;
int flow=;
while(bfs()) while(flow=dfs(s,INF)) mf+=flow;
return mf;
}
}dinic; int main()
{
cin>>n>>m;
dinic.init();
dinic.s=idx(,);
dinic.t=idx(n,m);
for(int i=;i<=n;i++)
{
for(int j=;j<m;j++)
{
scanf("%d",&w);
dinic.addedge(idx(i,j),idx(i,j+),w);
dinic.addedge(idx(i,j+),idx(i,j),w);
}
}
for(int i=;i<n;i++)
{
for(int j=;j<=m;j++)
{
scanf("%d",&w);
dinic.addedge(idx(i,j),idx(i+,j),w);
dinic.addedge(idx(i+,j),idx(i,j),w);
}
}
for(int i=;i<n;i++)
{
for(int j=;j<m;j++)
{
scanf("%d",&w);
dinic.addedge(idx(i,j),idx(i+,j+),w);
dinic.addedge(idx(i+,j+),idx(i,j),w);
}
}
cout<<dinic.maxflow()<<endl;
}
题解2:
首先在起点 $s$ 和终点 $t$ 之间再连一条直接相连的边,并且画出对偶图,如图:
将上图中标记删除的边删除,同时删掉之前添加的直接接连接起点和终点的边,得到如下图:
不难可以看出,从 $S$ 到 $T$ 的任意一条简单路径,都对应原图的一个 $s-t$ 割。而相应地,$s-t$ 最小割就对应着 $S$ 和 $T$ 间的最短路。
(当然,需要注意的一点是,在 $n=1$ 或者 $m=1$ 时对偶图比较特殊,需要特判一下)
AC代码:
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii;
const int INF=0x3f3f3f3f;
const int maxn=**+;
const int maxm=*maxn; int n,m,w; struct Edge{
int v,w;
int next;
};
Edge E[maxm];
int head[maxn],ne;
void init()
{
ne=;
memset(head,,sizeof(head));
}
void addedge(int u,int v,int w)
{
++ne;
E[ne].v=v, E[ne].w=w;
E[ne].next=head[u];
head[u]=ne;
} int dist[maxn];
bool vis[maxn];
void spfa(int s)
{
memset(dist,INF,sizeof(dist)); dist[s]=;
memset(vis,,sizeof(vis)); queue<int> Q;
Q.push(s), vis[s]=;
while(!Q.empty())
{
int u=Q.front(); Q.pop(); vis[u]=;
for(int i=head[u];i;i=E[i].next)
{
int v=E[i].v;
if(dist[v]>dist[u]+E[i].w)
{
dist[v]=dist[u]+E[i].w;
if(!vis[v]) Q.push(v), vis[v]=;
}
}
}
} int main()
{
cin>>n>>m;
init();
int S=, T=*(n-)*(m-)+;
int rowmin=INF, colmin=INF;
for(int i=;i<=n;i++)
{
for(int j=;j<m;j++)
{
scanf("%d",&w);
rowmin=min(rowmin,w);
if(i==) addedge(S,j,w), addedge(j,S,w);
else if(i==n)
{
int u=(*i-)*(m-)+j;
addedge(u,T,w), addedge(T,u,w);
}
else
{
int u=(*i-)*(m-)+j, v=(*i-)*(m-)+j;
addedge(u,v,w), addedge(v,u,w);
}
}
}
for(int i=;i<n;i++)
{
for(int j=;j<=m;j++)
{
scanf("%d",&w);
colmin=min(colmin,w);
if(j==)
{
int u=(*i-)*(m-)+j;
addedge(u,T,w), addedge(T,u,w);
}
else if(j==m)
{
int v=(*i-)*(m-)+(j-);
addedge(S,v,w), addedge(v,S,w);
}
else
{
int u=(*i-)*(m-)+(j-), v=(*i-)*(m-)+j;
addedge(u,v,w), addedge(v,u,w);
}
}
}
for(int i=;i<n;i++)
{
for(int j=;j<m;j++)
{
scanf("%d",&w);
int u=(*i-)*(m-)+j, v=(*i-)*(m-)+j;
addedge(u,v,w), addedge(v,u,w);
}
} if(n== && m==) cout<<<<endl;
else if(m==) cout<<colmin<<endl;
else if(n==) cout<<rowmin<<endl;
else
{
spfa(S);
cout<<dist[T]<<endl;
}
}
BZOJ 1001 - 狼抓兔子 - [Dinic最大流][对偶图最短路]的更多相关文章
- BZOJ 1001 狼抓兔子 (最小割转化成最短路)
1001: [BeiJing2006]狼抓兔子 Time Limit: 15 Sec Memory Limit: 162 MBSubmit: 27715 Solved: 7134[Submit][ ...
- bzoj 1001狼抓兔子(对偶图+最短路)最大流
推荐文章:<浅析最大最小定理在信息学竞赛中的应用>--周冬 题目 现在小朋友们最喜欢的"喜羊羊与灰太狼",话说灰太狼抓羊不到,但抓兔子还是比较在行的, 而且现在的兔子还 ...
- [BJOI2006]狼抓兔子——最小割转对偶图最短路
其实这个题直接Dinic跑最小割可过. (小优化是: 无向图建网络流,一条边不用建成4条,可以正反容量都是边权即可.完全等价 ) [无效]网络流之转换对偶图 一个巧妙的事情是,如果建边合适的话,最小割 ...
- BZOJ 1001 狼抓兔子 (网络流最小割/平面图的对偶图的最短路)
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1001 算法讨论: 1.可以用最大流做,最大流等于最小割. 2.可以把这个图转化其对偶图,然 ...
- BZOJ 1001 狼抓兔子 平面图的最小割
题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=1001 题目大意: 见链接 思路: 求最小割,平面图的最小割等价于对偶图的最短路 直接建 ...
- bzoj 1001 狼抓兔子 —— 平面图最小割(最短路)
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1001 平面图最小割可以转化成最短路问题: 建图时看清楚题目的 input ... 代码如下: ...
- BZOJ 1001 狼抓兔子
链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1001 现在小朋友们最喜欢的"喜羊羊与灰太狼",话说灰太狼抓羊不到,但抓兔子 ...
- 【BZOJ1001】狼抓兔子(平面图转对偶图,最短路)
[BZOJ1001]狼抓兔子(平面图转对偶图,最短路) 题面 BZOJ 洛谷 题解 这题用最小割可以直接做 今天再学习了一下平面图转对偶图的做法 大致的思路如下: 1.将源点到汇点中再补一条不与任何线 ...
- BZOJ 1001: [BeiJing2006]狼抓兔子【最大流/SPFA+最小割,多解】
1001: [BeiJing2006]狼抓兔子 Time Limit: 15 Sec Memory Limit: 162 MBSubmit: 23822 Solved: 6012[Submit][ ...
随机推荐
- 谈谈MySQL死锁之二 死锁检测和处理源码分析
这一篇主要是通过一个实验来进行描述,过程是比较枯燥的. 实验准备 create table test_lock(id int auto_increment primary key ,stock int ...
- IDEA使用笔记(四)——工具栏的显示隐藏切换
这也是在玩快捷键的时候,自己试验出来的,觉得不常用但是一旦想用了可能一下不知道怎么弄,还需要找,不如记下来,起码能加深一下印象!
- Nginx 限制访问速率
本文测试的nginx版本为nginx version: nginx/1.12.2 Nginx 提供了 limit_rate 和limit_rate_after,举个例子来说明一下在需要限速的站点 se ...
- latex学习(二)
1.我是在ubuntu18.04下安装的,使用的是清华的源:https://mirrors.tuna.tsinghua.edu.cn/help/CTAN/ 下载安装包:http://mirror.ct ...
- 译: 1. RabbitMQ Spring AMQP 之 Hello World
本文是译文,原文请访问:http://www.rabbitmq.com/tutorials/tutorial-one-spring-amqp.html RabbitMQ 是一个Brocker (消息队 ...
- Atitit web remote远程调试的原理attilax总结
Atitit web remote远程调试的原理attilax总结 Jvm是vm打开一个debug port,然后ide先连接..然后执行url,就会vm会与ide沟通.. Php的xdebug po ...
- linux每日命令(24):Linux 目录结构
一. 简介 对于每一个Linux学习者来说,了解Linux文件系统的目录结构,是学好Linux的至关重要的一步.,深入了解linux文件目录结构的标准和每个目录的详细功能,对于我们用好linux系统只 ...
- 《Essential C++》读书笔记 之 泛型编程风格
<Essential C++>读书笔记 之 泛型编程风格 2014-07-07 3.1 指针的算术运算(The Arithmetic of Pointer) 新需求1 新需求2 新需求3 ...
- 基于Python, Selenium, Phantomjs无头浏览器访问页面
引言: 在自动化测试以及爬虫领域,无头浏览器的应用场景非常广泛,本文将梳理其中的若干概念和思路,并基于代码示例其中的若干使用技巧. 1. 无头浏览器 通常大家在在打开网页的工具就是浏览器,通过界面上输 ...
- Android Launcher分析和修改4——初始化加载数据
上面一篇文章说了Launcher是如何被启动的,Launcher启动的过程主要是加载界面数据然后显示出来, 界面数据都是系统APP有关的数据,都是从Launcher的数据库读取,下面我们详细分析Lau ...