【BZOJ1001】狼抓兔子(BJOI2006)-平面图最小割转最短路

测试地址:狼抓兔子
做法:本题需要用到平面图最小割转最短路。
注意到题目中要求一个平面图的最小割,然而这个图点数太多,我们不可能直接用网络流求解,但是我们注意到,如果在平面图中每两个相邻区域之间连双向边(我们把右、上边界和左、下边界看做两个不相邻的平面区域),边的长度为这两个区域的公共边的权值,这时候我们发现,每一个割都对应了一条从右、上边界到左、下边界的路径,因此按这样建图之后跑最短路即可,因为SPFA会被卡,因此用Dijkstra实现即可,时间复杂度为O(nmlog(nm))。注意特判n=1m=1的情况。
以下是本人代码:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>
#define inf 1000000000
using namespace std;
int n,m,x,first[2000010]={0},tot=0,t,dis[2000010];
struct edge {int v,d,next;} e[12000010];
bool vis[2000010]={0};
struct point
{
    int val,id;
    bool operator < (point a) const
    {
        return val>a.val;
    }
};
priority_queue <point> Q;

void insert(int a,int b,int d)
{
    e[++tot].v=b;
    e[tot].d=d;
    e[tot].next=first[a];
    first[a]=tot;
}

void dijkstra()
{
    point now,nxt;
    now.val=0,now.id=0;
    vis[0]=1,dis[0]=0;
    for(int i=1;i<=t;i++) dis[i]=inf;
    for(int i=first[0];i;i=e[i].next)
    {
        nxt.val=e[i].d;
        nxt.id=e[i].v;
        dis[e[i].v]=e[i].d;
        Q.push(nxt);
    }
    while(!Q.empty())
    {
        now=Q.top();
        while(vis[now.id]&&!Q.empty()) Q.pop(),now=Q.top();
        if (Q.empty()) break;
        vis[now.id]=1;
        for(int i=first[now.id];i;i=e[i].next)
            if (dis[e[i].v]>dis[now.id]+e[i].d)
            {
                dis[e[i].v]=dis[now.id]+e[i].d;
                nxt.id=e[i].v;
                nxt.val=dis[e[i].v];
                Q.push(nxt);
            }
    }
}

int main()
{
    scanf("%d%d",&n,&m);

    t=2*(n-1)*(m-1)+1;
    int minx=inf;
    for(int i=1;i<m;i++)
    {
        scanf("%d",&x);
        minx=min(x,minx);
        insert(0,i,x);
    }
    for(int i=1;i<n-1;i++)
    {
        int s=(2*i-1)*(m-1);
        for(int j=1;j<m;j++)
        {
            scanf("%d",&x);
            minx=min(minx,x);
            insert(s+j,s+j+m-1,x);
            insert(s+j+m-1,s+j,x);
        }
    }
    for(int i=1;i<m;i++)
    {
        scanf("%d",&x);
        minx=min(minx,x);
        insert((2*n-3)*(m-1)+i,t,x);
    }
    for(int i=1;i<n;i++)
    {
        int s=(2*i-1)*(m-1);
        scanf("%d",&x);
        minx=min(minx,x);
        insert(s+1,t,x);
        for(int j=2;j<m;j++)
        {
            scanf("%d",&x);
            minx=min(minx,x);
            insert(s+j,s+j-m,x);
            insert(s+j-m,s+j,x);
        }
        scanf("%d",&x);
        minx=min(minx,x);
        insert(0,s,x);
    }
    for(int i=1;i<n;i++)
    {
        int s=(2*i-1)*(m-1);
        for(int j=1;j<m;j++)
        {
            scanf("%d",&x);
            minx=min(minx,x);
            insert(s+j,s+j-m+1,x);
            insert(s+j-m+1,s+j,x);
        }
    }

    if (n==1||m==1) {printf("%d",minx);return 0;}
    dijkstra();
    printf("%d",dis[t]);

    return 0;
}
posted @ 2017-11-24 16:06  Maxwei_wzj  阅读(108)  评论(0编辑  收藏  举报