• BZOJ-1001 狼抓兔子 (最小割-最大流)平面图转对偶图+SPFA


    1001: [BeiJing2006]狼抓兔子
    Time Limit: 15 Sec Memory Limit: 162 MB
    Submit: 14686 Solved: 3513
    [Submit][Status][Discuss]

    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只狼,才能完全封锁这条道路,你需要帮助狼王安排一个伏击方案,使得在将兔子一网打尽的前提下,参与的狼的数量要最小。因为狼还要去找喜羊羊麻烦.

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

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

    Sample Input
    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

    Sample Output
    14

    HINT
    2015.4.16新加数据一组,可能会卡掉从前可以过的程序。

    —————————————————华华丽丽的分割线————————————————-

    这道题一看就是最小割问题,而由最小割-最大流定理我们可以知道,平面图最小割=平面图最大流=对偶图的最短路
    然而我网络流并不是很会,正好这道题最大流会爆,故只能转对偶图跑最短路
    先说一下转对偶图的转法:
    这里用题目做解释:
    这里写图片描述
    将每个三角形看做一个节点,并分别编号1,2….,并设置两个节点,起点S和终点T,将每一条边割开,即连接各个点(三角形),新的边权等于被割掉的边的边权,然后跑SPFA即可
    分析得:
    对于横行:
    1.第一行割开后的点(三角形)都与终点T连边
    2.除去第一行和最后一行的其余割开后的两个相邻的点(三角形)连边
    3.最后一行的隔开后的点(三角形)都与起点S连边
    对于纵行:
    1.最左边的纵行割开后与起点S连边
    2.除最左最右边的纵行割开后的两个相邻点(三角形)连边
    3.最右边的纵行割开后与终点T连边
    对于斜行:
    1.割开后与相邻两点(三角形)连边
    (如上述图所示)
    最后跑S到T的最短路即可

    —————————————————华华丽丽的分割线————————————————-

    代码如下(关于图的转换,各个公式推一下就好,其实不是很麻烦):

    /**************************************************************
        Problem: 1001
        User: DaD3zZ
        Language: C++
        Result: Accepted
        Time:3428 ms
        Memory:124324 kb
    ****************************************************************/
    
    #include<queue>
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    bool visit[6000100]={false};
    int cnt=0,next[6000100]={0},point[6000100]={0},v[6000100]={0},cost[6000100]={0};
    int n,m,s,t;
    int dis[6000100];
    queue <int>que;
    
    void add(int a,int b,int c)
    {
        next[++cnt]=point[a];
        point[a]=cnt;
        v[cnt]=b;
        cost[cnt]=c;
    }
    
    int spfa()
    {
          memset(dis,127,sizeof(dis));
          int now,loc;
          dis[s]=0;
          que.push(s);
          visit[s]=true;
          while (!que.empty())
          {
              now=que.front();que.pop();
              visit[now]=false;loc=point[now];
              while (loc>0)
              {
                 if (dis[v[loc]]>dis[now]+cost[loc])
                  {
                      dis[v[loc]]=dis[now]+cost[loc];
                      if (visit[v[loc]]==false)
                      {
                          visit[v[loc]]=true; que.push(v[loc]);
                      }
                 }
                 loc=next[loc];       
             }  
         }  
        return dis[t];
    }//裸SPFA
    
    int main()
    {
        scanf("%d%d",&n,&m);
        s=0; t=(n-1)*(m-1)*2+1;
        for (int i=1; i<=m-1; i++)
            {
                int x;scanf("%d",&x);
                add(i*2,t,x);add(t,i*2,x);
            }
        for (int i=2; i<=n-1; i++)
            for (int j=1; j<=m-1; j++)
                {
                    int x;scanf("%d",&x);
                    add((i-1)*(m-1)*2+j*2,(i-1)*(m-1)*2+j*2-m*2+1,x);
                    add((i-1)*(m-1)*2+j*2-m*2+1,(i-1)*(m-1)*2+j*2,x);
                }
        for (int i=1; i<=m-1; i++)
            {
                int x;scanf("%d",&x);
                add((n-2)*2*(m-1)+i*2-1,s,x);
                add(s,(n-2)*2*(m-1)+i*2-1,x);
            }
        //横行的转换
        for (int i=1; i<=n-1; i++)
                {
                    int x; scanf("%d",&x);
                    add((i-1)*(m-1)*2+1,s,x);
                    add(s,(i-1)*(m-1)*2+1,x);
                    for (int j=1; j<=m-2; j++)
                        {
                            scanf("%d",&x);
                            add((i-1)*(m-1)*2+j*2+1,(i-1)*(m-1)*2+j*2,x);
                            add((i-1)*(m-1)*2+j*2,(i-1)*(m-1)*2+j*2+1,x);
                        }
                    scanf("%d",&x);
                    add((i-1)*(m-1)*2+(m-2)*2+2,t,x);
                    add(t,(i-1)*(m-1)*2+(m-2)*2+2,x);   
                }
        //竖行的转换
        for (int i=1; i<=n-1; i++)
            for (int j=1; j<=m-1; j++)
                {
                    int x;scanf("%d",&x);
                    add((i-1)*(m-1)*2+j*2-1,(i-1)*(m-1)*2+j*2,x);
                    add((i-1)*(m-1)*2+j*2,(i-1)*(m-1)*2+j*2-1,x);
                }
        //斜行的转换
        int ans=spfa();
        printf("%d",ans);
        return 0;
    }
  • 相关阅读:
    我藏在你的心里,你却不愿意寻找# BUG躲猫猫
    阴间需求之跨端登录
    神奇的props
    map与filter:你先我先?
    阴间BUG之动态路由刷新几率回首页
    阴间BUG之动态路由添加失败
    我在eltable就变了个模样,请你不要再想我,想起我
    SCP打包部署方法
    indexOf 与 includes
    YACC和BISON学习心得
  • 原文地址:https://www.cnblogs.com/DaD3zZ-Beyonder/p/5346245.html
Copyright © 2020-2023  润新知