【BZOJ1001】[BeiJing2006] 狼抓兔子

描述 Description

现在小朋友们最喜欢的 “喜羊羊与灰太狼”, 话说灰太狼抓羊不到,但抓兔子还是比较在行的,而且现在的兔子还比较笨,它们只有两个窝,现在你做为狼王,面对下面这样一个网格的地形:

左上角点为 (1,1), 右下角点为(N,M)(上图中 N=4,M=5). 有以下三种类型的道路 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 只狼,才能完全封锁这条道路,你需要帮助狼王安排一个伏击方案,使得在将兔子一网打尽的前提下,参与的狼的数量要最小。因为狼还要去找喜羊羊麻烦.

输入格式 InputFormat

第一行为 N,M. 表示网格的大小,N,M 均小于等于 1000. 接下来分三部分第一部分共 N 行,每行 M-1 个数,表示横向道路的权值. 第二部分共 N-1 行,每行 M 个数,表示纵向道路的权值. 第三部分共 N-1 行,每行 M-1 个数,表示斜向道路的权值. 输入文件保证不超过 10M.

输出格式 OutputFormat

输出一个整数,表示参与伏击的狼的最小数量.

样例输入 SampleInput

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

样例输出 SampleOutput

14


BZOJ 1001


代码 Code

试了一下平面图最小割转对偶图最短路的写法。所以以后还是必须得开循环队列么。

转对偶图的时候可以参考下面这张:

#include <stdio.h>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
#define inf 0x7fffffff/27.11
struct side
{
    int to,next,v;
};
side a[6000005];
int head[2000005];
int dis[2000005],f[6000005];
bool used[2000005];
int i,j,t,n,m,l,r,k,s,z,y,x,sn;
void add(int x,int y,int z)
{
    a[++sn].to=y;a[sn].v=z;a[sn].next=head[x];head[x]=sn;
    a[++sn].to=x;a[sn].v=z;a[sn].next=head[y];head[y]=sn;
}
void build()
{
    int i,j,t;
    //====================
    for (i=1;i<=m-1;i++)
    {
        scanf("%d",&t);
        add(2*i,z,t);
    }
    for (i=2;i<=n-1;i++)
    {
        for (j=1;j<=m-1;j++)
        {
            scanf("%d",&t);
            add((i-2)*2*(m-1)+2*j-1,(i-1)*2*(m-1)+2*j,t);
        }
    }
    for (i=1;i<=m-1;i++)
    {
        scanf("%d",&t);
        add(s,(n-2)*2*(m-1)+2*i-1,t);
    }
    //====================
    for (i=1;i<=n-1;i++)
    {
        scanf("%d",&t);
        add(s,(i-1)*2*(m-1)+1,t);
        for (j=2;j<=m-1;j++)
        {
            scanf("%d",&t);
            add((i-1)*2*(m-1)+2*j-2,(i-1)*2*(m-1)+2*j-1,t);
        }
        scanf("%d",&t);
        add((i-1)*2*(m-1)+2*(m-1),z,t);
    }
    //=====================
    for (i=1;i<=n-1;i++)
    {
        for (j=1;j<=m-1;j++)
        {
            scanf("%d",&t);
            add((i-1)*2*(m-1)+2*j-1,(i-1)*2*(m-1)+2*j,t);
        }
    }
}
void spfa()
{
    int i,j,t,k;
    l=0;r=l+1;f[l]=s;
    for (i=1;i<=z;i++) dis[i]=inf;
    memset(used,false,sizeof(used));
    used[s]=true;
    while (r!=l)
    {
        if (l>6000000) l-=6000000;
        t=f[l];l++;k=head[t];
        while (k!=0)
        {
            if (dis[a[k].to]>dis[t]+a[k].v)
            {
                dis[a[k].to]=dis[t]+a[k].v;
                if (used[a[k].to]==false) 
                {
                    used[a[k].to]=true;
                    f[r++]=a[k].to;
                    if (r==6000000) r-=6000000;
                }
            }
            k=a[k].next;
        }
        used[t]=false;
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    if (n==1 && m==1)
    {
        printf("0\n");
        return 0;
    }
    if (n==1)
    {
        t=0x7fffffff;
        for (i=1;i<=m-1;i++)
        {
            scanf("%d",&s);
            t=min(t,s);
        }
        printf("%d\n",t);
        return 0;
    }
    z=2*(n-1)*(m-1)+1;
    s=0;
    sn=0;
    memset(a,0,sizeof(a));
    memset(head,0,sizeof(head));
    build();
    spfa();
    printf("%d\n",dis[z]);
    return 0;
}