积水问题

有这样一块土地,可以被划分为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 }
原文地址:https://www.cnblogs.com/qianye/p/3055620.html