• bzoj 1001 狼抓兔子


    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1001

    题解:

      其实刚布置这道题的时候,我是拒绝的,后来听大犇们的的话,潜下心来学了一点(又经过数小时的调试之后)才写出了正解

      正解的概念表达是:利用平面图的性质,把最大流问题转化成最小割问题,再用最短路来解决(其实我也不懂这TM都是什么鬼)

    先介绍一下对偶图吧:

      对于每一个平面图G,都有一个对偶图G'与之对应,其构造方法如下:
      图G一个面为图G'中的一个点,图G中一条边的割线为图G'这条边两边两个面(所对应的点)之间的连线,边权也相等

      如果一条边只处于一个面内,就构造那个面自己连向自己的边(这条性质在这道题中并没有用到)

    对偶图构造样例(来自@Reddest):

    平面图G:

    对偶图G':

    得到平面图与对偶图之间的关系:对偶图的点数等于平面图的面数,对偶图的边数等于平面图的边数

    (更多证明以及性质定理之类的参见:http://wenku.baidu.com/link?url=RrUA5Y4dLzHhv_rO0UvuXeNnuOiGCryuYqQSRiBMurEevkJZ_kJcNueWMtqFTz7kZDbLFzVufYQNr_invfHnZnmIXTNED1W0rJ_Qab9YYhW

      那么,对于这道题来说还要再加几步:在构造对偶图之前在起点和终点之间连一条边,把最外层的面分成两半,一个作为起点,一个作为终点;

      构造过程中,不要构造起点和终点之间的边(其实虚拟出来的边没有边权,也没法构造)

    构造样例的对偶图:

    接着用各种算法求最短路即可

    我用的SPFA:

    #include<cstdio>
    #define MAXN 2000000
    #define INF 214748364
    int n,m,nn,heads[MAXN],d[MAXN],q[MAXN],head,tail,cnt;
    bool viss[MAXN];
    struct edge
    {
        int v,next,val;
    }e[MAXN*3];
    inline int min(int x,int y)
    {
        return x<y?x:y;
    }
    void add(int x,int y,int z)
    {
        e[++cnt]=(edge){y,heads[x],z};
        heads[x]=cnt;
    }
    void inedge()//建对偶图 
    {
        int x,cnt;
        //横边 
        for(int i=1;i<=m-1;i++)
        {
            scanf("%d",&x);
            add(0,i,x);add(i,0,x);
        }
        cnt=(m-1)*2;
        for(int i=2;i<n;i++)
        {
            for(int j=1;j<=m-1;j++)
            {
                cnt++;
                scanf("%d",&x);
                add(cnt,cnt-m+1,x);add(cnt-m+1,cnt,x);
            }
            cnt+=(m-1);
        }
        for(int i=1;i<=m-1;i++)
        {
            scanf("%d",&x);
            add(nn,nn-m+i,x);add(nn-m+i,nn,x);
        }
        //竖边 
        cnt=m;
        for(int i=1;i<=n-1;i++)
        {
            scanf("%d",&x);
            add(cnt,nn,x);add(nn,cnt,x);
            for(int j=2;j<m;j++)
            {
                cnt++;
                scanf("%d",&x);
                add(cnt,cnt-m,x);add(cnt-m,cnt,x);
            }
            scanf("%d",&x);
            add(0,cnt-m+1,x);add(cnt-m+1,0,x);
            cnt+=m;
        }
        //斜边 
        cnt=0;
        for(int i=1;i<=n-1;i++)
        {
            for(int j=1;j<=m-1;j++)
            {
                cnt++;
                scanf("%d",&x);
                add(cnt,cnt+m-1,x);add(cnt+m-1,cnt,x);
            }
            cnt+=(m-1);
        }
    }
    void SPFA()
    {
        head=1;tail=2;
        q[1]=0;
        viss[0]=true;
        while(head<tail)
        {
            for(int i=heads[q[head]];i;i=e[i].next)
            {
                if(d[q[head]]+e[i].val<d[e[i].v])
                {
                    d[e[i].v]=d[q[head]]+e[i].val;
                    if(!viss[e[i].v])
                    {
                        q[tail++]=e[i].v;
                        viss[e[i].v]=true;
                    }
                }
            }
            viss[q[head++]]=false;
        }
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        if(n==1)//特判
        {
            int x,ans=INF;
            for(int i=1;i<=m-1;i++)
            {
                scanf("%d",&x);
                ans=min(ans,x);
            }
            printf("%d
    ",ans==INF?0:ans);
            return 0;
        }
        else if(m==1)
        {
            int x,ans=INF;
            for(int i=1;i<=n-1;i++)
            {
                scanf("%d",&x);
                ans=min(ans,x);
            }
            printf("%d
    ",ans==INF?0:ans);
            return 0;
        }
        nn=(n-1)*(m-1)*2+1;
        inedge();
        for(int i=1;i<=nn;i++)d[i]=INF;
        SPFA();
        printf("%d
    ",d[nn]);
        return 0;
    }
  • 相关阅读:
    jQuery及javascript DOM创建节点(三)
    jQueryEasyUI Window的基本使用
    3.1、值类型
    手动依赖注入(二)
    3.1.2、字符类型
    不错不错
    我们应该讨论什么? 就面向对象的讨论所引发的一些思考
    保存个地址, 顺便问个问题~
    嗯嗯, 今天很高兴
    方法级AOP: 又一个补丁
  • 原文地址:https://www.cnblogs.com/xqmmcqs/p/5967115.html
Copyright © 2020-2023  润新知