zoukankan      html  css  js  c++  java
  • 积水问题

    有这样一块土地,可以被划分为M*N块正方形小块,每块面积是一平方英寸,第i行第j列的小块可以表示成P(i,j),这块土地高低不平,每一小块地P(i,j)都有自己的高度H(i,j),一场倾盆大雨后,由于这块地地势高低不同,许多低洼的地方都积存了不少降水,如果已经知道了这块土地的详细信息,求出它最多能积存多少立方英寸的降水


    分析:先分析一些比较容易求出的格子,例如边界,边界上积水上一定为0,从边界上最低的格子x开始,它就像是一个有洞的水桶,桶的容量取决于最低的那个洞,假设这个格子的高度为h,那么它相邻格子y的水位不会超过h,如果y的高度小于h,那么y的水位将是h,可以继续对y周围的格子进行灌水,直到这块水全部被高度大于h的地势包围起来,实际上是把高度大于h的地方和已经确定水位的地方看做是障碍物,然后从格子x开始做一次floodfill,则填好的格子水位全是h,并且这个格子周围的土地全部应该标记为已访问过,并把这些位置放入堆中。

    这样每次从堆中取出一个位置最低的点,处理它周围的点,直到堆的大小减为0。每个格子最多被访问一次,每次调整堆的操作时间复杂度为O(logmn),因此总的时间复杂度为O(mnlogmn)

      1 #include <stdio.h>
      2 #include <string.h>
      3 #define M 10
      4 #define N 10
      5 
      6 int map[M][N];                  /* 存储每块正方形的高度 */
      7 int flag[M][N];                 /* 表示禁止积水 */
      8 int treenode=0;                 /* 表示堆中节点个数 */
      9 int water=0;                    /* 记录注入的水量 */
     10 int m,n;
     11 struct node
     12 {
     13     int i,j;
     14     int height;                 /* 表示土地的高度 */
     15     node(){}
     16     node(int a, int b, int h){
     17         i=a;
     18         j=b;
     19         height=h;
     20     }
     21 };
     22 
     23 struct node tree[M*N];          /* 用来表示堆中节点 */
     24 
     25 void swap(node * a, node * b)
     26 {
     27     node t = *a;
     28     *a=*b;
     29     *b=t;
     30 }
     31 void siftdown(int i)
     32 {
     33     int c=i;
     34     if(2*i<=treenode)
     35         c=2*i+1;
     36     if(2*i+1<treenode && tree[2*i+1].height<tree[c].height)
     37         c=2*i+1;
     38     if(tree[i].height>tree[c].height)
     39     {
     40         swap(&tree[i],&tree[c]);
     41         siftdown(c);
     42     }
     43 }
     44 void siftup(int i)
     45 {
     46     while(i/2>0)
     47     {
     48         if(tree[i].height<tree[i/2].height)
     49             swap(&tree[i],&tree[i/2]);
     50         i/=2;
     51     }
     52 }
     53 
     54 void createTree()
     55 {
     56     for(int i=treenode/2;i>0;i--)
     57         siftdown(i);
     58 }
     59 
     60 /* 返回堆顶最小元素,并用最后一个元素替换,调整堆 */
     61 node deleteNode()
     62 {
     63     struct node temp=tree[1];
     64     tree[1]=tree[treenode--];
     65     siftdown(1);
     66     return temp;
     67 }
     68 /* 插入节点 */
     69 void insert(node t)
     70 {
     71     tree[++treenode]=t;
     72     siftup(treenode);
     73 }
     74 
     75 void slove()
     76 {
     77     /* 每次从堆中取出一个节点,并处理它周围的节点,直到堆的大小为0 */
     78     while(treenode>0)
     79     {
     80         node t = deleteNode();
     81         int a = t.i;
     82         int b = t.j;
     83         /* 处理上下左右四个方向的点 */
     84         if(a-1>=1 && !flag[a-1][b])
     85         {
     86             if(map[a-1][b]<t.height)
     87             {
     88                 water+=t.height-map[a-1][b];
     89                 map[a-1][b]=t.height;
     90             }
     91             /* 对位置进行标记 */
     92             flag[a-1][b]=1;
     93             insert(node(a-1,b,map[a-1][b]));
     94         }
     95         if(a+1<=m && !flag[a+1][b])
     96         {
     97             if(map[a+1][b]<t.height)
     98             {
     99                 water+=t.height-map[a+1][b];
    100                 map[a+1][b]=t.height;
    101             }
    102             flag[a+1][b]=1;
    103             insert(node(a+1,b,map[a+1][b]));
    104         }
    105         if(b-1>=1 && !flag[a][b-1])
    106         {
    107             if(map[a][b-1]<t.height)
    108             {
    109                 water+=t.height-map[a][b-1];
    110                 map[a][b-1]=t.height;
    111             }
    112             flag[a][b-1]=1;
    113             insert(node(a,b-1,map[a][b-1]));
    114         }
    115         if(b+1<=n && !flag[a][b+1])
    116         {
    117             if(map[a][b+1]<t.height)
    118             {
    119                 water+=t.height-map[a][b+1];
    120                 map[a][b+1]=t.height;
    121             }
    122             flag[a][b+1]=1;
    123             insert(node(a,b+1,map[a][b+1]));
    124         }
    125     }
    126 }
    127 
    128 int main()
    129 {
    130     freopen("in","r",stdin);
    131     memset(flag,0,sizeof(flag));
    132     scanf("%d%d",&m,&n);
    133     for(int i=1;i<=m;i++)
    134         for(int j=1;j<=n;j++)
    135             scanf("%d",&map[i][j]);
    136     for(int i=1;i<=m;i++)
    137     {
    138         insert(node(i,1,map[i][1]));
    139         flag[i][1]=1;
    140         insert(node(i,n,map[i][n]));
    141         flag[i][n]=1;
    142     }
    143 
    144     for(int i=2;i<n;i++)
    145     {
    146         insert(node(1,i,map[1][i]));
    147         flag[1][i]=1;
    148         insert(node(m,i,map[m][i]));
    149         flag[m][i]=1;
    150     }
    151     slove();
    152     printf("%d\n", water);
    153     return 0;
    154 }
  • 相关阅读:
    马拉车算法
    n皇后问题(回溯算法)
    求解最大升序子序列问题(动态规划)
    利用二进制进行快速乘法:俄罗斯农名乘法
    Redis、MySQL、Hive、Hbase的区别,数据库和数据仓库的区别
    MySQL数据库
    算法工程师的Bug与Debug
    复习KNN并实现
    文本领域数据增强技术
    Fasttext模型总结
  • 原文地址:https://www.cnblogs.com/qianye/p/2801683.html
Copyright © 2011-2022 走看看