BZOJ 1001 [BeiJing2006]狼抓兔子
2017.08.19
2017.08.19
给你一堆(无限个)兔子,从一个网格图的左上方的点跑到右下方的点。每个店有一个最大流量,如果你想截断这条路就需要花费流量同样的价格。求最小花费使得这一堆兔子到不了右下角。
这道题直接上最小割竟!然!可!以!A! 之后就是板子
正解对偶图,之后会进行重构。
#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int INF=1<<30;
int n,m,S,T,inx,ans,depth[2000010];
int to[6000010],nex[6000010],val[6000010],tot=1,head[2000010];
queue<int>q;
const int getid(int tx,int ty) {return (tx-1)*m+ty;}
void addedge(int tx,int ty,int tz)
{
to[++tot]=ty,nex[tot]=head[tx],head[tx]=tot,val[tot]=tz;
to[++tot]=tx,nex[tot]=head[ty],head[ty]=tot,val[tot]=tz;
}
bool bfs()
{
while(!q.empty()) q.pop();
q.push(S);
memset(depth,-1,sizeof depth);
depth[S]=0;
while(!q.empty())
{
int tmp=q.front();
q.pop();
for(int i=head[tmp];i;i=nex[i])
if(val[i]&&depth[to[i]]==-1)
{
depth[to[i]]=depth[tmp]+1;
if(to[i]==T) return true;
q.push(to[i]);
}
}
return false;
}
int dinic(int pos,int left)
{
if(pos==T) return left;
int nleft=left;
for(int i=head[pos];i;i=nex[i])
if(val[i]&&depth[to[i]]==depth[pos]+1)
{
int tmp=dinic(to[i],min(nleft,val[i]));
if(!tmp) depth[to[i]]=-1;
nleft-=tmp;
val[i]-=tmp;
val[i^1]+=tmp;
if(!nleft) break;
}
return left-nleft;
}
int main()
{
scanf("%d%d",&n,&m);
S=1,T=getid(n,m);
for(int i=1;i<=n;++i)
for(int j=2;j<=m;++j)
{
scanf("%d",&inx);
int tmp=getid(i,j);
addedge(tmp-1,tmp,inx);
}
for(int i=2;i<=n;++i)
for(int j=1;j<=m;++j)
{
scanf("%d",&inx);
addedge(getid(i,j),getid(i-1,j),inx);
}
for(int i=2;i<=n;++i)
for(int j=2;j<=m;++j)
{
scanf("%d",&inx);
addedge(getid(i,j),getid(i-1,j-1),inx);
}
while(bfs()) ans+=dinic(S,INF);
printf("%d\n",ans);
return 0;
}