• 洛谷 P4001 [ICPC-Beijing 2006]狼抓兔子


    题目描述

    现在小朋友们最喜欢的"喜羊羊与灰太狼",话说灰太狼抓羊不到,但抓兔子还是比较在行的,而且现在的兔子还比较笨,它们只有两个窝,现在你做为狼王,面对下面这样一个网格的地形:

    左上角点为(1,1),右下角点为(N,M)(上图中N=3,M=4).有以下三种类型的道路

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

    输入格式

    第一行为N,M.表示网格的大小,N,M均小于等于1000.

    接下来分三部分

    第一部分共N行,每行M-1个数,表示横向道路的权值.

    第二部分共N-1行,每行M个数,表示纵向道路的权值.

    第三部分共N-1行,每行M-1个数,表示斜向道路的权值.

    输出格式

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

    输入输出样例

    输入 #1
    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
    输出 #1
    14

    思路:这个题是一道很显然的最小割,可以用最小割最大流定理去证明,最小割=最大流,然后用dinic解决该问题。然而我们看看数据范围,n,m<=1000,也就是说节点数量高达10^6,
    很显然朴素的dinic是过不了的,然而因为
    本题数据过于水,所以对dinic在加一些玄学优化也是能过得去的。然而,我这里要说一个对这类问题的一个最为有效的方法:平面图转对偶图。
    对偶图的解释请参考相关书籍,这里不详细介绍。从题目中我们可以发现题目中给的图具有特殊性质,即每个方格都可以分成两个三角形,且这些方格与这些方格分成的三角形呈网格状排列,
    这其实对于一个平面图来说,转换为其对应的对偶图是相对容易的,我们可以将原图中的起点S与终点T之间连一条线,这条线包围的面就作为对偶图的终点,而起点就是其全集的补。
    建图比较复杂,写在main函数里面了。另外还要对n==1或m==1的情况进行特判。
      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<algorithm>
      5 #include<queue>
      6 using namespace std;
      7 const int N = 2e6 + 10;
      8 const int M = 6e6 + 10;
      9 int read()
     10 {
     11     int ret = 0;
     12     char ch = getchar();
     13     while(ch < '0' || ch > '9') ch = getchar();
     14     while(ch >= '0' && ch <= '9')
     15     {ret = ret * 10 + ch - '0'; ch = getchar();}
     16     return ret;
     17 }
     18 struct edge{
     19     int to, nxt, dis;
     20 }e[M << 1];
     21 int head[N], tot = 0;
     22 void adde(int f, int t, int d)
     23 {
     24     e[++ tot] = (edge){t, head[f], d};
     25     head[f] = tot;
     26 }
     27 int n, m, st, ed;
     28 int dist[N], vis[N];
     29 struct node{
     30     int id, dis;
     31     bool operator < (const node A) const{
     32         return A.dis < dis;
     33     }
     34 };
     35 priority_queue <node> q;
     36 void dij()
     37 {
     38     memset(dist, 0x3f, sizeof dist);
     39     memset(vis, 0, sizeof vis);
     40     q.push((node){st, 0});
     41     dist[st] = 0;
     42     while(!q.empty())
     43     {
     44         int u = q.top().id;
     45         q.pop();
     46         if(vis[u]) continue;
     47         vis[u] = 1;
     48         for(int i = head[u]; i; i = e[i].nxt)
     49         {
     50             int v = e[i].to;
     51             if(dist[v] > dist[u] + e[i].dis)
     52             {
     53                 dist[v] = dist[u] + e[i].dis;
     54                 q.push((node){v, dist[v]});
     55             }
     56         }
     57     }
     58 }
     59 int val(int r, int c, int tmp)
     60 {
     61     return (r - 1) * (m - 1) + c + tmp * (m - 1) * (n - 1);
     62 }
     63 int main()
     64 {
     65     scanf("%d%d", &n, &m);
     66     //if(n == 1 || m == 1) {printf("1
    "); return 0;}
     67     int x;
     68     int minn = 0x3f3f3f3f;
     69     st = 0, ed = 2 * m * n + 1;
     70     for(int i = 1; i <= n; i ++)
     71         for(int j = 1; j <= m - 1; j ++)
     72         {
     73             scanf("%d", &x);
     74             minn = min(minn, x);
     75             if(i == 1)
     76             {
     77                 adde(val(i, j, 0), st, x);
     78                 adde(st, val(i, j, 0), x);
     79             }
     80             else if(i == n)
     81             {
     82                 adde(ed, val(i - 1, j, 1), x);
     83                 adde(val(i - 1, j, 1), ed, x);
     84             }
     85             else
     86             {
     87                 adde(val(i, j, 0), val(i - 1, j, 1), x);
     88                 adde(val(i - 1, j, 1), val(i, j, 0), x);
     89             }
     90         }
     91     for(int i = 1; i <= n - 1; i ++)
     92         for(int j = 1; j <= m; j ++)
     93         {
     94             scanf("%d", &x);
     95             minn = min(minn, x);
     96             if(j == 1)
     97             {
     98                 adde(ed, val(i, j, 1), x);
     99                 adde(val(i, j, 1), ed, x);
    100             }
    101             else if(j == m)
    102             {
    103                 adde(val(i, j - 1, 0), st, x);
    104                 adde(st, val(i, j - 1, 0), x);
    105             }
    106             else
    107             {
    108                 adde(val(i, j, 1), val(i, j - 1, 0), x);
    109                 adde(val(i, j - 1, 0), val(i, j, 1), x);
    110             }
    111         }
    112     for(int i = 1; i <= n - 1; i ++)
    113         for(int j = 1; j <= m - 1; j ++)
    114         {
    115             scanf("%d", &x);
    116             adde(val(i, j, 0), val(i, j, 1), x);
    117             adde(val(i, j, 1), val(i, j, 0), x);
    118         }
    119     dij();
    120     if(n == 1 || m == 1) printf("%d
    ", minn);
    121     else printf("%d
    ", dist[ed]);
    122     return 0;
    123 }
    
    
    
     
  • 相关阅读:
    android的dex,odex,oat,vdex,art文件格式
    windows写时复制处理流程
    .NET 6中读取配置文件内容
    .net core 配置文件
    C# 格式化json
    .net 安全
    07. 图像的翻转、旋转、仿射变换、透视变换
    05. 绘制基本的图像
    03. Pillow包解决opencv中文乱码
    08. 滤波(卷积、均值、高斯、中值、双边滤波)
  • 原文地址:https://www.cnblogs.com/loi-frank/p/11898355.html
Copyright © 2020-2023  润新知