bzoj1001 狼抓兔子
题目
题解
网络流很经典的建模,先建对偶图,再用最短路跑最小割,注意以左下为s,右上为t
代码
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#define N 6001000
#define M 2000010
using namespace std;
int n,m,s,t;
int read()
{
int cnt=0;char ch=getchar();
while (!isdigit(ch)) ch=getchar();
while (isdigit(ch)) cnt=cnt*10+ch-'0',ch=getchar();
return cnt;
}
int num,a[N],b[N],w[N],nt[N],p[M];
void add(int x,int y,int v)
{
a[++num]=x;b[num]=y;w[num]=v;
nt[num]=p[x];p[x]=num;
a[++num]=y;b[num]=x;w[num]=v;
nt[num]=p[y];p[y]=num;
}
int up(int x,int y) {return (x-1)*(m-1)*2+y;}
int down(int x,int y) {return (x-1)*(m-1)*2+(m-1)+y;}
void build()
{
s=0;t=(m-1)*(n-1)*2+1;
for(int i=1;i<=n;i++)
for(int j=1;j<m;j++)
{
int v=read();
if(i==1) add(up(i,j),t,v);
else if(i==n) add(s,down(i-1,j),v);
else add(down(i-1,j),up(i,j),v);
}
for(int i=1;i<n;i++)
for(int j=1;j<=m;j++)
{
int v=read();
if(j==1) add(s,down(i,j),v);
else if(j==m) add(up(i,j-1),t,v);
else add(up(i,j-1),down(i,j),v);
}
for(int i=1;i<n;i++)
for(int j=1;j<m;j++)
{
int v=read();
add(up(i,j),down(i,j),v);
}
}
int dis[M];bool flag[M];queue<int> q;
void spfa()
{
memset(dis,127,sizeof(dis));
q.push(s);flag[s]=1;dis[s]=0;
while(!q.empty())
{
int k=q.front();q.pop();
for(int e=p[k];e;e=nt[e])
{
int kk=b[e];
if(dis[kk]-dis[k]>w[e])
{
dis[kk]=dis[k]+w[e];
if(!flag[kk]) {flag[kk]=1;q.push(kk);}
}
}
flag[k]=0;
}
}
int main()
{
n=read();m=read();
build();
spfa();
printf("%d",dis[t]);
return 0;
}