//种子填充算法的运用之积水问题
//把最外围的各个点当作边界,从边界中选出高度最低的点a(高度为h1),
//把a从边界数组中删除,找到a周围的点,如果周围的点b满足没有遍历过且没有越界,进入第4行的种子填充floodfill(b,h1)
//b点做上遍历了的记号,判断b的体积h是否小于h1,如果h不小于于h1,则把b当作边界,并放入边界数组中,返回第2行。否则总的积水再加上h1-h,找到b周围的点,如果周围的点c满足没有遍历过且没有越界,进入第4行的种子填充floodfill(c,h1)
//对于点数量很多的可以采用堆结构
//
#include<stdio.h>
#include<conio.h>
#define N 10
struct point
//点
{
int x,y;
}boundary[N*N+1]; //boundary边界
bool mark[N][N]; //点是否遍历过,true遍历了 false未遍历
int h[N][N]; //点的高度
int lineNum; //点的列数
int columNum; //点的行数
int boundaryNum=0; //边界个数
int total=0; //积水总量
const int X[4]={0,1,0,-1},Y[4]={1,0,-1,0};
//点的四个移动方向
void init()
//初始化得到数据和边界信息
{
int i,j,k=1;
freopen("d:\\in.txt","r",stdin);
scanf("%d %d",&columNum,&lineNum);
for(i=1;i<=columNum;i++)
{
for(j=1;j<=lineNum;j++)
{
scanf("%d",&h[i][j]);
mark[i][j]=false;
if(i==1||j==1||i==columNum||j==lineNum)
{
boundary[++boundaryNum].x=j;
boundary[boundaryNum].y=i;
mark[i][j]=true;
}
}
}
}
point delBoundary()
//找出最小的体积的边界,删除并返回它
{
int i,min=1;
point t;
for(i=2;i<=boundaryNum;i++)
{
if(h[boundary[i].y][boundary[i].x]<h[boundary[min].y][boundary[min].x])
{
min=i;
}
}
t=boundary[min];
for(i=min;i<boundaryNum;i++)
//数组往前移动
{
boundary[i]=boundary[i+1];
}
boundaryNum--;
return t;
}
void floodfill(point a,int h1)
//边界填充或累加体积
{
int i;
point b;
mark[a.y][a.x]=true;
if(h[a.y][a.x]<h1)
{
total+=h1-h[a.y][a.x];
for(i=0;i<4;i++)
//点周围的点进行种子填充
{
b.x=a.x+X[i];
b.y=a.y+Y[i];
if(b.x>=1&&b.x<=lineNum&&b.y>=1&&b.y<=columNum&&mark[b.y][b.x]==false)
{
floodfill(b,h1);
}
}
}
else
{
boundary[++boundaryNum]=a;
return ;
}
}
void solve()
{
int i;
point a,b;
int h1;
while(boundaryNum)
{
a=delBoundary();
h1=h[a.y][a.x];
for(i=0;i<4;i++)
{
b.x=a.x+X[i];
b.y=a.y+Y[i];
if(b.x>1&&b.x<lineNum&&b.y>1&&b.y<columNum&&mark[b.y][b.x]==false)
{
floodfill(b,h1);
}
}
}
}
int main()
{
init();
solve();
freopen("d:\\out.txt","w",stdout);
printf("%d",total);
return 0;
}