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][ ...
随机推荐
- OpenCV 学习笔记 05 人脸检测和识别
本节将介绍 Haar 级联分类器,通过对比分析相邻图像区域来判断给定图像或子图像与已知对象是否匹配. 本章将考虑如何将多个 Haar 级联分类器构成一个层次结构,即一个分类器能识别整体区域(如人脸) ...
- shiny: Web Application Framework for R
shiny: Web Application Framework for R 基于R语言的一个web框架,适用于数据分析与图表绘画展示类型的网站.
- GIT无法自动忽略YellowRV1.1.uvgui.Administrator文件的解决方法
原来这个YellowRV1.1.uvgui.Administrator文件是在.gitignore之前被提交进服务器的,.gitignore对已经存在服务器里的文件是不起作用的.按照回答里投票最高的答 ...
- java解惑--摘要
(1)下面是一个试图解决上述问题的程序,它会打印出什么呢?public class Change{public static void main(String args[]){System.out.p ...
- 赋值文件夹名称为日期的doc命令
copy D:\111.txt d:\%date:~0,4%年%date:~5,2%月%date:~8,2%日.*
- 安装配置OSA运维管理平台
1.下载完整包V1.0.2wget http://www.osapub.com/download/OSA_BETA_V1.0.2.tar.gzV1.0.5wget http://www.osapub. ...
- android开发的童鞋们 你该学点C++
更多关于C++的知识点,请关注android开发应该学点C++(索引贴)android开发应该学点C++(其他) (*android开发论坛----android开发学习----android开发*) ...
- 第三部分:Android 应用程序接口指南---第五节:计算---第一章 RenderScript
第1章 RenderScript RenderScript提供一个独立于平台并在本地运行的计算引擎,用它来加速你需要大量计算能力的应用.RenderScript是一个运行与Android上计算密集型的 ...
- FFmpeg: AVPacket 结构体分析
AVPacket是FFmpeg中很重要的一个数据结构,它保存了解封装之后,解码之前的数据(注意:仍然是压缩后的数据)和关于这些数据的一些附加信息,如显示时间戳(pts).解码时间戳(dts).数据时长 ...
- 每日英语:Dashing the China Dream
Much has been said about what the 'China Dream' really means to many Chinese -- whether it is nation ...