bzoj1001 狼抓兔子

题目

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;
}
posted @ 2017-08-18 11:05  XYZinc  阅读(154)  评论(0编辑  收藏  举报