• 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
    ",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
    ",dis[2*(m-1)*(n-1)+1]);//(2*(m-1)*(n-1)+1)号点为终点(右下角) 
    return 0;
    }

    后记:

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

      ①LittleRewriter(洛谷题解)

      ②kafuuchino 机房的CRK大佬

  • 相关阅读:
    20180925-2 功能测试
    【PL/SQL编程】循环语句
    【PL/SQL编程】条件语句
    【PL/SQL编程】变量和常量
    【PL/SQL编程】数据类型说明
    【PL/SQL编程】注释说明
    【PL/SQL编程】SQL与PL/SQL的区别
    【SQL查询】查询结果翻译成其他值_decode
    【SQL查询】日期的转换_to_date/to_char
    【SQL查询】视图_view
  • 原文地址:https://www.cnblogs.com/lck-lck/p/9671189.html
Copyright © 2020-2023  润新知