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][ ...
随机推荐
- linux达人养成计划学习笔记(七)—— 用户登录查看命令
一.查看用户登录信息 1.命令格式 w 2.命令结果 第一行信息是:系统当前时间 系统运行总时间 登录用户数量 一分钟/五分钟/十分钟的系统负载(越大越差) 二.who命令 1 ...
- JS中 HTMLEncode和HTMLDecode
<!--js伪编码解码--><script language="javascript" type="text/javascript">f ...
- android开发的童鞋们 你该学点C++
更多关于C++的知识点,请关注android开发应该学点C++(索引贴)android开发应该学点C++(其他) (*android开发论坛----android开发学习----android开发*) ...
- 常用七种排序的python实现
1 算法复杂度 算法复杂度分为时间复杂度和空间复杂度.其中, 时间复杂度是指执行算法所需要的计算工作量:而空间复杂度是指执行这个算法所需要的内存空间. 算法的复杂性体现在运行该算法时的计算机所需资源的 ...
- Approx Analytic Arealight
试着实现的基于分析方法的近似面积光源.
- 【Android】开源项目UniversalImageLoader及开源框架ImageLoader
UniversalImageLoader 简单来说就是用于加载图片的一个开源项目,在其项目介绍中是这么写的 支持多线程图片加载 提供丰富的细节配置,比如线程池大小,HTPP请求项,内存和磁盘缓存,图片 ...
- 【Socket】关于socket长连接的心跳包
TCP的socket本身就是长连接的,那么为什么还要心跳包呢? 在smack里有个30s发送一个空消息的线程,同样关于心跳包(keepalive) 据网络搜索到的资料解释如下 内网机器如果不主动向外发 ...
- Java多线程系列——信号量:Semaphore
简介 信号量为多线程协作提供了更为强大的控制方法.也可以说,信号量是对锁的扩展.无论是内部锁 synchronized 还是重入锁 ReentrantLock,一次都只允许一个线程访问一个资源,而信号 ...
- golang获取命令行参数
部署golang项目时难免要通过命令行来设置一些参数,那么在golang中如何操作命令行参数呢?可以使用os库和flag库. 1.golang os库获取命令行参数 os可以通过变量Args来获取命令 ...
- portfolio
1.工作量计算逻辑: 原始待办事项: 预估2个冲刺,如下图所示: Sprint1的故事点计划工作量5,空闲工作量28.如下图 Sprint2为预估冲刺,指的是预估待办事项在后续冲刺的预估计划,后续冲刺 ...