• [BZOJ1001] [Beijing2006] 狼抓兔子 (最短路)


    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新加数据一组,可能会卡掉从前可以过的程序。

    Solution

      乍一看是一道网络流的题,但是实际写完会发现超时超到姥姥家去了。
      定理:平面图的最大流=该图对偶图的最短路,某形象解释见某贴心神犇
      之后SPFA乱搞或Dijkstra乱搞,不过我建边的方式有点鬼畜。
     
      1 #include <cstdio>
      2 #include <cstring>
      3 using namespace std;
      4 struct node
      5 {
      6     int v, w;
      7 }edge[6000005];
      8 int fst[2000005], nxt[6000005], sss, ttt, dis[2000005], q[2000005], front, back;
      9 bool inq[2000005];
     10  
     11 void qscanf(int &x)
     12 {
     13     char c = getchar();
     14     x = 0;
     15     while(c < '0' || c > '9')
     16         c = getchar();
     17     while(c >= '0' && c <= '9')
     18         x = x * 10 + c - '0', c = getchar();
     19 }
     20  
     21 void addedge(int i, int u, int v, int w)
     22 {
     23     edge[i << 1] = (node){v, w}, nxt[i << 1] = fst[u], fst[u] = i << 1;
     24     edge[i << 1 | 1] = (node){u, w}, nxt[i << 1 | 1] = fst[v], fst[v] = i << 1 | 1;
     25 }
     26  
     27 void SPFA()
     28 {
     29     memset(dis, 63, sizeof(dis));
     30     dis[sss] = 0, inq[sss] = q[++back] = sss;
     31     while(front != back)
     32     {
     33         int u = q[++front % 2000000];
     34         inq[u] = false, front %= 2000000;
     35         for(int i = fst[u]; i; i = nxt[i])
     36         {
     37             int v = edge[i].v, w = edge[i].w;
     38             if(dis[v] > dis[u] + w)
     39             {
     40                 dis[v] = dis[u] + w;
     41                 if(!inq[v])
     42                 {
     43                     dis[v] = dis[u] + w;
     44                     inq[v] = true;
     45                     q[++back % 2000000] = v;
     46                     back %= 2000000;
     47                 }
     48             }
     49         }
     50     }
     51 }
     52  
     53 int main()
     54 {
     55     int n, m, etot = 0;
     56     qscanf(n), qscanf(m);
     57     n--, m--;
     58     if(n && m)
     59     {
     60         sss = n * m * 2 + 1, ttt = n * m * 2 + 2;
     61         for(int i = 1; i <= n + 1; i++)
     62             for(int j = 1; j <= m; j++)
     63             {
     64                 int u = ((i - 2) * m + j) * 2 - 1, v = ((i - 1) * m + j) * 2, w;
     65                 qscanf(w);
     66                 if(i == 1)
     67                     addedge(++etot, sss, v, w);
     68                 else if(i == n + 1)
     69                     addedge(++etot, u, ttt, w);
     70                 else
     71                     addedge(++etot, u, v, w);
     72             }
     73         for(int i = 1; i <= n; i++)
     74             for(int j = 1; j <= m + 1; j++)
     75             {
     76                 int u = ((i - 1) * m + j) * 2 - 2, v = ((i - 1) * m + j) * 2 - 1, w;
     77                 qscanf(w);
     78                 if(j == 1)
     79                     addedge(++etot, ttt, v, w);
     80                 else if(j == m + 1)
     81                     addedge(++etot, u, sss, w);
     82                 else
     83                     addedge(++etot, u, v, w);
     84             }
     85         for(int i = 1; i <= n; i++)
     86             for(int j = 1; j <= m; j++)
     87             {
     88                 int u = ((i - 1) * m + j) * 2 - 1, v = ((i - 1) * m + j) * 2, w;
     89                 qscanf(w), addedge(++etot, u, v, w);
     90             }
     91         SPFA();
     92     }
     93     else
     94     {
     95         if(m)
     96             n = m;
     97         dis[ttt] = 2147483647;
     98         for(int i = 1; i <= n; i++)
     99         {
    100             qscanf(fst[i]);
    101             if(dis[ttt] > fst[i])
    102                 dis[ttt] = fst[i];
    103         }
    104     }
    105     printf("%d
    ", dis[ttt]);
    106     return 0;
    107 }
    View Code
  • 相关阅读:
    日常学习——FFT
    poj 3353 Road Construction tarjan 边双联通分支 缩点+结论
    4612 warm up tarjan+bfs求树的直径(重边的强连通通分量)忘了写了,今天总结想起来了。
    tarjan总结
    hdu 4655 Cut Pieces 找规律
    POJ3592 Instantaneous Transference tarjan +spfa
    hdu 4647 Another Graph Game
    hdu4638 group 树状数组
    4630 no pain no game 树状数组
    hdu 4619 Warm up 2 网络流 最小割
  • 原文地址:https://www.cnblogs.com/CtrlCV/p/5350850.html
Copyright © 2020-2023  润新知