http://www.byvoid.com/blog/poi-1999-wod/zh-hans/
根据木桶原理,水位的高低取决于最低的边界。我们可以从最低的边界入手,向内灌水,使水面于边界齐平。如果灌到了新的边界,而且不低于最低的边界,则这个点一定是不能被灌水的。
可以想象成一个深度搜索的过程,我们从最低边界开始灌水,遇到比最低边界低的,它的水平面顶多就是最低边界,直到遇到一个边界比最低边界高的,将高边界放入优先队列中。
每次取边界最小值向内灌水,于是可以用一个最小堆来维护高度。
算法流程如下:
/*
* Problem: POI1999 wod
* Author: Guo Jiabao
* Time: 2008.12.16 21:44:50
* State: Solved
*/
#include
#include
#include
#include
#include
using namespace std;
const int MAX=101;
const int dx[4]={0,0,-1,1},dy[4]={1,-1,0,0};
struct point
{
int x,y;
};
int N,M,All;
int Alt[MAX][MAX];
bool vid[MAX][MAX];
int heap_size;
point Heap[MAX*MAX];
void heap_ins(int x,int y)
{
int i;
for (i=++heap_size;Alt[x][y] Alt[Heap[c].x][Heap[c].y])
Heap[i]=Heap[c];
else
break;
}
Heap[i]=M;
return R;
}
void init()
{
freopen("wod.in","r",stdin);
freopen("wod.out","w",stdout);
scanf("%d%d",&N,&M);
for (int i=1;i<=N;i++)
for (int j=1;j<=M;j++)
scanf("%d",&Alt[i][j]);
Alt[0][0]=-0x7FFFFFFF;
Heap[heap_size=0].x=Heap[0].y=0;
}
inline bool inrange(point A)
{
return A.x>=1 && A.x<=N && A.y>=1 && A.y<=M;
}
void floodfill(point A,int h)
{
point B;
vid[A.x][A.y]=true;
if (Alt[A.x][A.y]>=h)
heap_ins(A.x,A.y);
else
{
All+=h-Alt[A.x][A.y];
for (int i=0;i<4;i++)
{
B.x=A.x+dx[i]; B.y=A.y+dy[i];
if (inrange(B) && !vid[B.x][B.y])
floodfill(B,h);
}
}
}
void solve()
{
int i,j;
point A,B;
for (i=1;i<=N;i++)
{
heap_ins(i,1);
heap_ins(i,M);
vid[i][1]=vid[i][M]=true;
}
for (i=2;i<=M-1;i++)
{
heap_ins(1,i);
heap_ins(N,i);
vid[1][i]=vid[N][i]=true;
}
while (heap_size)
{
A=heap_delmin();
for (i=0;i<4;i++)
{
B.x=A.x+dx[i]; B.y=A.y+dy[i];
if (inrange(B) && !vid[B.x][B.y])
floodfill(B,Alt[A.x][A.y]);
}
}
}
int main()
{
init();
solve();
printf("%d",All);
return 0;
}
先考虑我们的土地是一维的,首先定义两个数字,left,right
left[i]记录的是从0~i-1最高的高度,right[i]记录的是从n~i+1最高的高度
那么i的水平面高度是,min(left[i], right[i]) - h[i]
https://github.com/codingtest/interview/blob/master/code2.cpp
#include
#include
#include
#include
#include
#include