题目描述
现在小朋友们最喜欢的"喜羊羊与灰太狼",话说灰太狼抓羊不到,但抓兔子还是比较在行的,而且现在的兔子还比较笨,它们只有两个窝,现在你做为狼王,面对下面这样一个网格的地形:
左上角点为(1,1),右下角点为(N,M)(上图中N=3,M=4).有以下三种类型的道路
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只狼,才能完全封锁这条道路,你需要帮助狼王安排一个伏击方案,使得在将兔子一网打尽的前提下,参与的狼的数量要最小。因为狼还要去找喜羊羊麻烦。
输入输出格式
输入格式:第一行为N,M.表示网格的大小,N,M均小于等于1000.
接下来分三部分
第一部分共N行,每行M-1个数,表示横向道路的权值.
第二部分共N-1行,每行M个数,表示纵向道路的权值.
第三部分共N-1行,每行M-1个数,表示斜向道路的权值.
输出格式:输出一个整数,表示参与伏击的狼的最小数量.
输入输出样例
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
14
证明:1.最大流不可能大于最小割, 因为最大流所有的水流都一定经过最小割那些割边, 流过的水流怎么可能比水管容量还大呢?
2.最大流不可能小于最小割, 如果小, 那么说明水管容量没有物尽其用, 可以继续加大水流.
注:此题还可以将 平面图 变为 对偶图 ,再跑 spfa,求出最小割。
附代码:
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<queue>
#define MAXN 1000010
#define MAXM 1010
#define MAX 999999999
using namespace std;
int n,m,s,t,c=1;
int head[MAXN],deep[MAXN],id[MAXM][MAXM];
bool vis[MAXN];
struct node{
int next,to,w;
}a[MAXN*6];
inline int read(){
int date=0,w=1;char c=0;
while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
return date*w;
}
inline void add(int u,int v,int w){
a[c].to=v;a[c].w=w;
a[c].next=head[u];
head[u]=c++;
a[c].to=u;a[c].w=w;
a[c].next=head[v];
head[v]=c++;
}
bool bfs(){
int u,v;
queue<int> q;
for(int i=1;i<=t;i++)deep[i]=0;
deep[s]=1;
q.push(s);
while(!q.empty()){
u=q.front();
q.pop();
for(int i=head[u];i;i=a[i].next){
v=a[i].to;
if(a[i].w&&!deep[v]){
deep[v]=deep[u]+1;
if(v==t)return true;
q.push(v);
}
}
}
return false;
}
int dfs(int x,int limit){
if(x==t)return limit;
int v,sum,cost=0;
for(int i=head[x];i;i=a[i].next){
v=a[i].to;
if(a[i].w&&deep[v]==deep[x]+1){
sum=dfs(v,min(limit-cost,a[i].w));
if(sum>0){
a[i].w-=sum;
a[i^1].w+=sum;
cost+=sum;
if(limit==cost)break;
}
else deep[v]=-1;
}
}
return cost;
}
int dinic(){
int ans=0;
while(bfs())
ans+=dfs(s,MAX);
return ans;
}
int main(){
int w;
n=read();m=read();
s=1;t=n*m;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
id[i][j]=c++;
c=2;
for(int i=1;i<=n;i++)
for(int j=1;j<m;j++){
w=read();
add(id[i][j],id[i][j+1],w);
}
for(int i=1;i<n;i++)
for(int j=1;j<=m;j++){
w=read();
add(id[i][j],id[i+1][j],w);
}
for(int i=1;i<n;i++)
for(int j=1;j<m;j++){
w=read();
add(id[i][j],id[i+1][j+1],w);
}
printf("%d\n",dinic());
return 0;
}