有这样一块土地,可以被划分为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 }