P4001 [BJOI2006]狼抓兔子

传送门

思路:

  不少题解都是用网络流来做最小割(网络流是什么),但对于一个不会网络流的蒟蒻来做这题相当困难。

  听机房daolao说可以重构图做最短路。然后就baidu将平面图转换成一个对偶图,因为网络流的最小割 = 对偶图的最短路,所以只要在对偶图上跑最短路(从左上角跑到右下角)就行了。

  由于堆优化的Dijkstra写炸了,冒着“死亡”的风险码了个Spfa的最短路,开了O2竟然卡进800ms。

AC代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<string>
#include<queue>
#include<vector>
#include<map>
#include<stack>
#include<deque>
#include<set>
using namespace std;
#define maxn 2000005
#define INF 0x3f3f3f3f
int cnt,n,m,w;
int head[maxn],vis[maxn],dis[maxn];
queue <int> q;
struct hh
{    
    int to,nex,dis;
}t[maxn<<2];
inline int read()
{
    char kr=0;
    char ls;
    for(;ls>'9'||ls<'0';kr=ls,ls=getchar());
    int xs=0;
    for(;ls>='0'&&ls<='9';ls=getchar())
    {
        xs=(xs<<3)+(xs<<1)+ls-48;
    }
    if(kr=='-') xs=0-xs;
    return xs;
} 
inline void clear()//初始化 
{
    cnt=0;
    memset(vis,false,sizeof(vis));
    memset(dis,INF,sizeof(dis));
    memset(head,-1,sizeof(head));
} 
inline void add(int nex,int to,int dis)//前向星建图 
{
    t[cnt]=hh{to,head[nex],dis};
    head[nex]=cnt++;     
    t[cnt]=hh{nex,head[to],dis};
    head[to]=cnt++;
}
inline void getmap()//将平面图转换为对偶图
{
    for(int j=1;j<m;++j)//给每块标号 
    {
        w=read();
        add(0,j*2,w);
    }
    for(int i=2;i<n;++i)
    {
        for(int j=1;j<m;++j)
        {
            w=read();
            add(2*(i-2)*(m-1)+j*2-1,2*(i-1)*(m-1)+j*2,w);
        }
    }
    if(n>=2)
    for(int j=1;j<m;++j)
    {
        w=read();
        add(2*(n-2)*(m-1)+j*2-1,2*(n-1)*(m-1)+1,w);
    }
    for(int i=1;i<n;++i)
    {
        for(int j=1;j<=m;++j)
        {
            w=read();
            if(j==1) add(2*(n-1)*(m-1)+1,2*(i-1)*(m-1)+1,w);
            else if(j==m) add(2*i*(m-1),0,w);
            else add(2*(i-1)*(m-1)+(j-1)*2,2*(i-1)*(m-1)+(j-1)*2+1,w);
        }
    }
    for(int i=1;i<n;++i)
    {
        for(int j=1;j<m;++j)
        {
            w=read();
            add(2*(i-1)*(m-1)+(j-1)*2+1,2*(i-1)*(m-1)+j*2,w);
        }
    }
}
int main()
{
    clear();
    n=read();m=read();
    if(n==1 || m==1)
    {
        if(n>m) swap(n,m);
        int ans=INF;
        for(int i=1;i<m;++i)
        {
            w=read();
            ans=min(ans,w);
        }
        if(ans==INF) ans=0;//特判只有全图只有一个点的情况 
        printf("%d\n",ans);
        return 0;
    }
    getmap();
    dis[0]=0;vis[0]=1;//编号为 0 的点为起始点(左上角) 
    q.push(0);
    while(!q.empty())
    {
        int u=q.front();q.pop();
        vis[u]=0;
        for (int i=head[u];i!= -1;i=t[i].nex)
        {
            int v=t[i].to,w=t[i].dis;
            if (dis[v]>dis[u]+w)
            {
                dis[v] = dis[u] + w;
                if (!vis[v])
                {
                    vis[v] = 1;
                    q.push(v);
                }
            }
        }
    }
    printf("%d\n",dis[2*(m-1)*(n-1)+1]);//(2*(m-1)*(n-1)+1)号点为终点(右下角) 
return 0;
}

后记:

  因为蒟蒻水平有限,AC这题借鉴了两位大佬的bolg:

  ①LittleRewriter(洛谷题解)

  ②kafuuchino 机房的CRK大佬

posted @ 2018-09-18 20:21  落笔映惆怅丶  阅读(164)  评论(0编辑  收藏  举报