[bzoj1001][BeiJing2006]狼抓兔子

Description

给出一张网格,左上角点为(1,1),右下角点为(N,M).有以下三种类型的道路
1:(x,y)<==>(x+1,y)
2:(x,y)<==>(x,y+1)
3:(x,y)<==>(x+1,y+1)
截断一条边的代价为它的权值,求最小的代价使得从左上角不可到达右下角。

Solution

很明显最小割就好了。
写个dinic练练手。(好久没写网络流了)
注意这里的边是双向边。

Code

#include<cstdio>
#include<cstring>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define rep(i,a) for(int i=last[a];i;i=next[i])
#define N 1000005
using namespace std;
const int inf=0x7fffffff;
int n,m,x,l,S,T,ans,last[N],dis[N],d[N],next[N*6],v[N*6],t[N*6];
void add(int x,int y,int z) {
    t[++l]=y;v[l]=z;next[l]=last[x];last[x]=l;
    t[++l]=x;v[l]=z;next[l]=last[y];last[y]=l;
}
int get(int x,int y) {return (x-1)*m+y;}
bool bfs() {
    memset(dis,0,sizeof(dis));dis[S]=1;
    int i=0,j=1;d[1]=S;
    while (i<j) rep(k,d[++i]) 
        if (!dis[t[k]]&&v[k]) 
            dis[t[k]]=dis[d[i]]+1,d[++j]=t[k];
    return dis[T];
}
int dinic(int x,int y) {
    if (x==T) return y;
    int now=0;
    rep(i,x) if (dis[t[i]]==dis[x]+1&&v[i]) {
        int k=dinic(t[i],min(y,v[i]));
        v[i]-=k;v[i^1]+=k;y-=k;now+=k;
        if (!y) break;
    }
    if (!now) dis[x]=-1;
    return now;
}
int main() {
    scanf("%d%d",&n,&m);S=1;T=n*m;l=1;
    fo(i,1,n) fo(j,1,m-1) scanf("%d",&x),add(get(i,j),get(i,j+1),x);
    fo(i,1,n-1) fo(j,1,m) scanf("%d",&x),add(get(i,j),get(i+1,j),x);
    fo(i,1,n-1) fo(j,1,m-1) scanf("%d",&x),add(get(i,j),get(i+1,j+1),x);
    while (bfs()) ans+=dinic(S,inf);
    printf("%d",ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值