题目大意:有n*m个网格点,坐标为(i,j)的点与(i+1,j),(i,j+1),(i+1,j+1zu)间有权值w的无向边,表示该边可通过兔子 的最大数量,左上和右下分别为兔子起点和终点。一头狼阻只能挡一只兔子,求要阻挡兔子到达终点的最小狼数量。
思路:最小割。。。。注意所开数组的大小,很容易mle和re。
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<queue>
using namespace std;
queue<int>q;
int n,m,dp[1000010];
int p[12000010],nex[12000010],head[1000010],c[12000010],e;
void add(int a,int b,int w){
p[e]=b;
nex[e]=head[a];
head[a]=e;
c[e++]=w;
}
int id(int x,int y){
return x*m+y;
}
int mi(long long a,long long b){
if(a>b) return b;
else return a;
}
int bfs(int s,int t){
int u,v,i;
for(i=0;i<=1000005;i++) dp[i]=1e9;
dp[s]=0;
for(q.push(s);!q.empty();q.pop()){
u=q.front();
for(i=head[u];i;i=nex[i]){
v=p[i];
if(dp[v]>dp[u]+1&&c[i]){
dp[v]=dp[u]+1;
q.push(v);
}
}
}
return dp[t]!=1e9;
}
long long dfs(int u,long long flow){
if(u==id(n-1,m-1)||flow==0) return flow;
long long i,v,sum=0,f;
for(i=head[u];i;i=nex[i]){
v=p[i];
if(dp[v]==dp[u]+1){
f=dfs(v,mi(flow-sum,c[i]));
c[i]-=f;
c[i^1]+=f;
sum+=f;
}
if(sum==flow) break;
}
if(sum==0) dp[u]=1e9;
return sum;
}
int main(){
int i,j,k;
// freopen("in.txt","r",stdin);
scanf("%d%d",&n,&m);
e=2;
for(i=0;i<n;i++){
for(j=0;j<m-1;j++){
scanf("%d",&k);
int x=id(i,j),y=id(i,j+1);
add(x,y,k);
add(y,x,0);
add(y,x,k);
add(x,y,0);
}
}
for(i=0;i<n-1;i++){
for(j=0;j<m;j++){
scanf("%d",&k);
int x=id(i,j),y=id(i+1,j);
add(x,y,k);
add(y,x,0);
add(y,x,k);
add(x,y,0);
}
}
for(i=0;i<n-1;i++){
for(j=0;j<m-1;j++){
scanf("%d",&k);
int x=id(i,j),y=id(i+1,j+1);
add(x,y,k);
add(y,x,0);
add(y,x,k);
add(x,y,0);
}
}
long long ans=0;
while(bfs(0,id(n-1,m-1))) ans+=dfs(0,1e18);
printf("%lld\n",ans);
return 0;
}