您的位置:首页 > 其它

BZOJ 1001: [BeiJing2006]狼抓兔子

2014-03-15 17:03 387 查看
题目地址:http://www.lydsy.com/JudgeOnline/problem.php?id=1001

题目大意:见原题&算法讨论。

算法讨论:

        很容易看出这是最小割。

        我们首先想到的是最小割=最大流。

        但是点数最多有1e6,用O(n^2*m)的Dinic和O(n*m^2)的sap显然都是要超时的。(据说Dinic也能过?)

        于是我们想到了另一个公式:平面图最大流=对偶图最短路。

        网格图做对偶图是很方便的啦~

        然后SPFA就更方便了啦~

Code:

/*
* Problem:1001
* Author:PYC
*/

#include <cstdio>

#define Vnum (1000*1000*2)
#define Enum (1000*1000*5*2)
#define maxn 2000100
#define oo (1<<30)
#define Bnum 1100
#define ooo 2147483647

using namespace std;

int n,m,mm,son[Vnum],next[Enum],ed[Enum],data[Enum],end,h=0,t=1,q[maxn],dis[maxn],tt=1,id[Bnum][Bnum][2];
bool v[maxn];

inline int min(int x,int y){
return x<y?x:y;
}

inline void INSERT(int x,int y,int z){
mm++;
next[mm]=son[x];
son[x]=mm;
ed[mm]=y;
data[mm]=z;
}

inline void insert(int x,int y,int z){
INSERT(x,y,z);
INSERT(y,x,z);
}

void spfa(){
for (int i=2;i<=end;++i) dis[i]=oo;
v[1]=1;
q[1]=1;
while (h!=t){
h++;
h%=maxn;
v[q[h]]=0;
int x=q[h];
for (int i=son[x];i;i=next[i]){
int y=ed[i];
if (dis[x]+data[i]<dis[y]){
dis[y]=dis[x]+data[i];
if (!v[y]){
t++;
t%=maxn;
v[y]=1;
q[t]=y;
}
}
}
}
}

int main(){
scanf("%d%d",&n,&m);
if (n==1 && m==1){
printf("0\n");
return 0;
}
if (n==1){
int ans=ooo;
for (int i=1;i<=m-1;++i){
int x;
scanf("%d",&x);
ans=min(ans,x);
}
printf("%d\n",ans);
return 0;
}
if (m==1){
int ans=ooo;
for (int i=1;i<=n-1;++i){
int x;
scanf("%d",&x);
ans=min(ans,x);
}
printf("%d\n",ans);
return 0;
}
for (int i=1;i<=n-1;++i)
for (int j=1;j<=m-1;++j){
++tt;
id[i][j][0]=tt;
++tt;
id[i][j][1]=tt;
}
end=tt+1;
for (int i=1;i<=n;++i)
for (int j=1;j<=m-1;++j){
int x;
scanf("%d",&x);
if (i==1){
insert(1,id[i][j][0],x);
continue;
}
if (i==n){
insert(end,id[i-1][j][1],x);
continue;
}
insert(id[i][j][0],id[i-1][j][1],x);
}
for (int i=1;i<=n-1;++i)
for (int j=1;j<=m;++j){
int x;
scanf("%d",&x);
if (j==1){
insert(end,id[i][j][1],x);
continue;
}
if (j==m){
insert(1,id[i][j-1][0],x);
continue;
}
insert(id[i][j-1][0],id[i][j][1],x);
}
for (int i=1;i<=n-1;++i)
for (int j=1;j<=m-1;++j){
int x;
scanf("%d",&x);
insert(id[i][j][0],id[i][j][1],x);
}
spfa();
printf("%d\n",dis[end]);
return 0;
}
By Charlie Pan

Mar 15,2014
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息