1001: [BeiJing2006]狼抓兔子
Time Limit: 15 Sec
Memory Limit: 162 MB
Submit: 14389
Solved: 3462
[ Submit][ Status][ Discuss]
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
解题思路:
首先先建个图(无向图)然后就是最小割。
Dinic之前打的太low了,选到了逆天的优化。
#include<cstdio>
#include<iostream>
#include<cstring>
using
namespace
std;
int
n,m;
int
sg,tg;
int
len=0;
struct
data
{
int
to,v,next;
}e[6100000];
int
h[1100000];
int
lian[6100000];
int
dis[1100000];
int
q[1100000];
void
insert(
int
x,
int
y,
int
w)
{
++len;
e[len].to=y;
e[len].v=w;
e[len].next=h[x];
h[x]=len;
}
bool
bfs()
{
memset
(dis,0,
sizeof
(dis));
dis[1]=1;
int
tail=1; q[tail]=1;
int
head=0;
while
(head<tail)
{
++head;
int
u=h[q[head]];
while
(u!=0)
{
if
(dis[e[u].to]==0 && e[u].v)
{
dis[e[u].to]=dis[q[head]]+1;
++tail; q[tail]=e[u].to;
}
u=e[u].next;
}
}
if
(dis[tg]!=0)
return
1;
else
return
dis[tg];
}
int
dinic(
int
now,
int
sum)
{
if
(now==tg)
return
sum;
int
u=h[now];
int
used=0;
while
(u!=0)
{
int
ss;
if
(e[u].v && dis[e[u].to]==dis[now]+1 && (ss=dinic(e[u].to,min(e[u].v,sum-used)))&& ss)//这一步的优化十分重要。
{
e[u].v-=ss;
e[lian[u]].v+=ss;
used+=ss;
if
(used==sum)
return
used;
}
u=e[u].next;
}
if
(used==0) dis[now]=-1;//也是个优化。
return
used;
}
int
main()
{
scanf
(
"%d %d"
,&n,&m);
for
(
int
i=1;i<=n;++i)
for
(
int
j=1;j<=m-1;++j)
{
int
x;
scanf
(
"%d"
,&x);
insert((i-1)*m+j,(i-1)*m+j+1,x); lian[len]=len+1;
insert((i-1)*m+j+1,(i-1)*m+j,x); lian[len]=len-1;
}
for
(
int
i=1;i<=n-1;++i)
for
(
int
j=1;j<=m;++j)
{
int
x;
scanf
(
"%d"
,&x);
insert((i-1)*m+j,(i-1)*m+j+m,x); lian[len]=len+1;
insert((i-1)*m+j+m,(i-1)*m+j,x); lian[len]=len-1;
}
for
(
int
i=1;i<=n-1;++i)
for
(
int
j=1;j<=m-1;++j)
{
int
x;
scanf
(
"%d"
,&x);
insert((i-1)*m+j,(i-1)*m+j+m+1,x); lian[len]=len+1;
insert((i-1)*m+j+m+1,(i-1)*m+j,x); lian[len]=len-1;
}
sg=1; tg=n*m;
int
ans=0;
while
(bfs())
{
ans+=dinic(1,0x7fffffff);
}
printf
(
"%d"
,ans);
}