所以我有一个任务,我必须重新创建一个3d棋盘,这是一个RxC正方形网格,每个正方形都是不同的高度。如果棋盘是水密的,并且有人在它上面浇水直到它不能再容纳水,它将保持固定量的水。如果电路板已经保持其最大水量,则任何多余的水倒在电路板上都会从边缘排出,电路板周围没有高大的容器。你可以假设棋盘上的方格是一平方英寸,高度是以英寸为单位。
int CalcContainedWater( const int *p_data, int num_columns, int num_rows )
其中p_data
是指向连续的二维,行主要有符号整数数组的第一个元素的指针。您的功能将针对不同形状和内容的电路板的参考实现进行测试,以确定其正确性。
请注意p_data
内的值可以包含高度的正值和负值。
例如:
A)以下板块的收容率为3.
1, 1, 1, 1, 1,
1, 0, 0, 0, 1,
1, 1, 1, 1, 1,
B)以下板块的收容率为0.
1, 0, 1,
1, 0, 1,
1, 1, 1,
C)以下板块的收容率为1.
0, 1, 0,
1, 0, 1,
0, 1, 0,
这是我到目前为止所拥有的:
#include "stdafx.h"
#include <queue>
#include <vector>
using namespace std;
enum GridPosition
{
TOP_LEFT_CORNER,
TOP_RIGHT_CORNER,
BOTTOM_LEFT_CORNER,
BOTTOM_RIGHT_CORNER,
TOP_ROW,
BOTTOM_ROW,
LEFT_COLUMN,
RIGHT_COLUMN,
FREE,
};
struct Square
{
int nHeight;
int nPos;
GridPosition gPos;
bool bIsVisited;
bool bIsFenced;
bool bIsFlooding;
Square(){ nHeight = 0; nPos = 0; gPos = FREE; bIsVisited = false; bIsFenced = false; bIsFlooding = false;};
~Square(){};
Square( int Height, int Pos, GridPosition GridPos, bool Visited, bool Fenced, bool Flooding)
{
nHeight = Height;
nPos = Pos;
gPos = GridPos;
bIsVisited = Visited;
bIsFenced = Fenced;
bIsFlooding = Flooding;
}
};
template< typename FirstType, typename SecondType >
struct PairComparator
{
bool operator()( const pair<FirstType, SecondType>& p1,
const pair<FirstType, SecondType>& p2 ) const
{
return p1.second > p2.second;
}
};
int CalcContainedWater( const int *p_data, int num_columns, int num_rows );
int CalcContainedWater( const int *p_data, int num_columns, int num_rows )
{
priority_queue<pair<int,int>, vector<pair<int,int>>, PairComparator<int,int>> qPerimeter;
queue<pair<int,int>> qFlooding;
vector<Square> vSquareVec(num_columns * num_rows);
int nTotalContained = 0;
int nCurrentSqHeight = 0;
int nCurrWaterLvl = 0;
int nDepth = 1;
for( int nRow = 0; nRow < num_rows; ++nRow)
{
for( int nColumn = 0; nColumn < num_columns; ++ nColumn)
{
int nCurrArrayPoint = nRow * num_columns + nColumn;
nCurrentSqHeight = p_data[nCurrArrayPoint];
Square sSquare(nCurrentSqHeight, nCurrArrayPoint, FREE, false,false,false);
if(nRow == 0 && nColumn == 0)
sSquare.gPos = TOP_LEFT_CORNER;
else if(nRow == 0 && nColumn == num_columns - 1)
sSquare.gPos = TOP_RIGHT_CORNER;
else if(nRow == num_rows - 1 && nColumn == 0)
sSquare.gPos = BOTTOM_LEFT_CORNER;
else if(nRow == num_rows - 1 && nColumn == num_columns - 1)
sSquare.gPos = BOTTOM_RIGHT_CORNER;
else if( nRow == 0)
sSquare.gPos = TOP_ROW;
else if( nRow == num_rows -1 )
sSquare.gPos = BOTTOM_ROW;
else if( nColumn == 0)
sSquare.gPos = LEFT_COLUMN;
else if( nColumn == num_columns - 1)
sSquare.gPos = RIGHT_COLUMN;
vSquareVec[nCurrArrayPoint] = sSquare;
if( nRow == 0 || nColumn == 0 ||
nColumn == num_columns - 1 || nRow == num_rows -1 )
{
sSquare.bIsFenced = true;
vSquareVec[nCurrArrayPoint] = sSquare;
pair<int,int> p1(nCurrArrayPoint, nCurrentSqHeight);
qPerimeter.push(p1);
}
}
}
nCurrWaterLvl = qPerimeter.top().second;
while( !qPerimeter.empty() )
{
pair<int,int> PerimPos = qPerimeter.top();
qPerimeter.pop();
if( !vSquareVec[PerimPos.first].bIsVisited )
{
if( vSquareVec[PerimPos.first].nHeight > nCurrWaterLvl )
nCurrWaterLvl = vSquareVec[PerimPos.first].nHeight;
vSquareVec[PerimPos.first].bIsFlooding = true;
qFlooding.push(PerimPos);
while( !qFlooding.empty() )
{
pair<int,int> FloodPos = qFlooding.front();
qFlooding.pop();
nDepth = nCurrWaterLvl - vSquareVec[FloodPos.first].nHeight;
if( nDepth >= 0)
{
vSquareVec[FloodPos.first].bIsVisited = true;
pair<int,int> newFloodPos;
switch(vSquareVec[FloodPos.first].gPos)
{
case TOP_LEFT_CORNER:
if( !vSquareVec[FloodPos.first + 1].bIsVisited &&
!vSquareVec[FloodPos.first + 1].bIsFlooding)
{
vSquareVec[FloodPos.first + 1].bIsFlooding = true;
newFloodPos.first = vSquareVec[FloodPos.first + 1].nPos;
newFloodPos.second = vSquareVec[FloodPos.first + 1].nHeight;
qFlooding.push(newFloodPos);
}
if( !vSquareVec[FloodPos.first + num_rows].bIsVisited &&
!vSquareVec[FloodPos.first + num_rows].bIsFlooding)
{
vSquareVec[FloodPos.first + num_rows].bIsFlooding = true;
newFloodPos.first = vSquareVec[FloodPos.first + num_rows].nPos;
newFloodPos.second = vSquareVec[FloodPos.first + num_rows].nHeight;
qFlooding.push(newFloodPos);
}
break;
case TOP_RIGHT_CORNER:
if( !vSquareVec[FloodPos.first - 1].bIsVisited &&
!vSquareVec[FloodPos.first - 1].bIsFlooding)
{
vSquareVec[FloodPos.first - 1].bIsFlooding = true;
newFloodPos.first = vSquareVec[FloodPos.first - 1].nPos;
newFloodPos.second = vSquareVec[FloodPos.first - 1].nHeight;
qFlooding.push(newFloodPos);
}
if( !vSquareVec[FloodPos.first + num_rows].bIsVisited &&
!vSquareVec[FloodPos.first + num_rows].bIsFlooding)
{
vSquareVec[FloodPos.first + num_rows].bIsFlooding = true;
newFloodPos.first = vSquareVec[FloodPos.first + num_rows].nPos;
newFloodPos.second = vSquareVec[FloodPos.first + num_rows].nHeight;
qFlooding.push(newFloodPos);
}
break;
case BOTTOM_LEFT_CORNER:
if( !vSquareVec[FloodPos.first + 1].bIsVisited &&
!vSquareVec[FloodPos.first + 1].bIsFlooding)
{
vSquareVec[FloodPos.first + 1].bIsFlooding = true;
newFloodPos.first = vSquareVec[FloodPos.first + 1].nPos;
newFloodPos.second = vSquareVec[FloodPos.first + 1].nHeight;
qFlooding.push(newFloodPos);
}
if( !vSquareVec[FloodPos.first - num_rows].bIsVisited &&
!vSquareVec[FloodPos.first - num_rows].bIsFlooding)
{
vSquareVec[FloodPos.first - num_rows].bIsFlooding = true;
newFloodPos.first = vSquareVec[FloodPos.first - num_rows].nPos;
newFloodPos.second = vSquareVec[FloodPos.first - num_rows].nHeight;
qFlooding.push(newFloodPos);
}
break;
case BOTTOM_RIGHT_CORNER:
if( !vSquareVec[FloodPos.first - 1].bIsVisited &&
!vSquareVec[FloodPos.first - 1].bIsFlooding)
{
vSquareVec[FloodPos.first - 1].bIsFlooding = true;
newFloodPos.first = vSquareVec[FloodPos.first - 1].nPos;
newFloodPos.second = vSquareVec[FloodPos.first - 1].nHeight;
qFlooding.push(newFloodPos);
}
if( !vSquareVec[FloodPos.first - num_rows].bIsVisited &&
!vSquareVec[FloodPos.first - num_rows].bIsFlooding)
{
vSquareVec[FloodPos.first - num_rows].bIsFlooding = true;
newFloodPos.first = vSquareVec[FloodPos.first - num_rows].nPos;
newFloodPos.second = vSquareVec[FloodPos.first - num_rows].nHeight;
qFlooding.push(newFloodPos);
}
break;
case TOP_ROW:
if( !vSquareVec[FloodPos.first - 1].bIsVisited &&
!vSquareVec[FloodPos.first - 1].bIsFlooding)
{
vSquareVec[FloodPos.first - 1].bIsFlooding = true;
newFloodPos.first = vSquareVec[FloodPos.first - 1].nPos;
newFloodPos.second = vSquareVec[FloodPos.first - 1].nHeight;
qFlooding.push(newFloodPos);
}
if( !vSquareVec[FloodPos.first + 1].bIsVisited &&
!vSquareVec[FloodPos.first + 1].bIsFlooding)
{
vSquareVec[FloodPos.first + 1].bIsFlooding = true;
newFloodPos.first = vSquareVec[FloodPos.first + 1].nPos;
newFloodPos.second = vSquareVec[FloodPos.first + 1].nHeight;
qFlooding.push(newFloodPos);
}
if( !vSquareVec[FloodPos.first + num_rows].bIsVisited &&
!vSquareVec[FloodPos.first + num_rows].bIsFlooding)
{
vSquareVec[FloodPos.first + num_rows].bIsFlooding = true;
newFloodPos.first = vSquareVec[FloodPos.first + num_rows].nPos;
newFloodPos.second = vSquareVec[FloodPos.first + num_rows].nHeight;
qFlooding.push(newFloodPos);
}
break;
case BOTTOM_ROW:
if( !vSquareVec[FloodPos.first - 1].bIsVisited &&
!vSquareVec[FloodPos.first - 1].bIsFlooding)
{
vSquareVec[FloodPos.first - 1].bIsFlooding = true;
newFloodPos.first = vSquareVec[FloodPos.first - 1].nPos;
newFloodPos.second = vSquareVec[FloodPos.first - 1].nHeight;
qFlooding.push(newFloodPos);
}
if( !vSquareVec[FloodPos.first + 1].bIsVisited &&
!vSquareVec[FloodPos.first + 1].bIsFlooding)
{
vSquareVec[FloodPos.first + 1].bIsFlooding = true;
newFloodPos.first = vSquareVec[FloodPos.first + 1].nPos;
newFloodPos.second = vSquareVec[FloodPos.first + 1].nHeight;
qFlooding.push(newFloodPos);
}
if( !vSquareVec[FloodPos.first - num_rows].bIsVisited &&
!vSquareVec[FloodPos.first - num_rows].bIsFlooding)
{
vSquareVec[FloodPos.first - num_rows].bIsFlooding = true;
newFloodPos.first = vSquareVec[FloodPos.first - num_rows].nPos;
newFloodPos.second = vSquareVec[FloodPos.first - num_rows].nHeight;
qFlooding.push(newFloodPos);
}
break;
case LEFT_COLUMN:
if( !vSquareVec[FloodPos.first + 1].bIsVisited &&
!vSquareVec[FloodPos.first + 1].bIsFlooding)
{
vSquareVec[FloodPos.first + 1].bIsFlooding = true;
newFloodPos.first = vSquareVec[FloodPos.first + 1].nPos;
newFloodPos.second = vSquareVec[FloodPos.first + 1].nHeight;
qFlooding.push(newFloodPos);
}
if( !vSquareVec[FloodPos.first + num_rows].bIsVisited &&
!vSquareVec[FloodPos.first + num_rows].bIsFlooding)
{
vSquareVec[FloodPos.first + num_rows].bIsFlooding = true;
newFloodPos.first = vSquareVec[FloodPos.first + num_rows].nPos;
newFloodPos.second = vSquareVec[FloodPos.first + num_rows].nHeight;
qFlooding.push(newFloodPos);
}
if( !vSquareVec[FloodPos.first - num_rows].bIsVisited &&
!vSquareVec[FloodPos.first - num_rows].bIsFlooding)
{
vSquareVec[FloodPos.first - num_rows].bIsFlooding = true;
newFloodPos.first = vSquareVec[FloodPos.first - num_rows].nPos;
newFloodPos.second = vSquareVec[FloodPos.first - num_rows].nHeight;
qFlooding.push(newFloodPos);
}
break;
case RIGHT_COLUMN:
if( !vSquareVec[FloodPos.first - 1].bIsVisited &&
!vSquareVec[FloodPos.first - 1].bIsFlooding)
{
vSquareVec[FloodPos.first - 1].bIsFlooding = true;
newFloodPos.first = vSquareVec[FloodPos.first - 1 ].nPos;
newFloodPos.second = vSquareVec[FloodPos.first - 1].nHeight;
qFlooding.push(newFloodPos);
}
if( !vSquareVec[FloodPos.first + num_rows].bIsVisited &&
!vSquareVec[FloodPos.first + num_rows].bIsFlooding)
{
vSquareVec[FloodPos.first + num_rows].bIsFlooding = true;
newFloodPos.first = vSquareVec[FloodPos.first + num_rows].nPos;
newFloodPos.second = vSquareVec[FloodPos.first + num_rows].nHeight;
qFlooding.push(newFloodPos);
}
if( !vSquareVec[FloodPos.first - num_rows].bIsVisited &&
!vSquareVec[FloodPos.first - num_rows].bIsFlooding)
{
vSquareVec[FloodPos.first - num_rows].bIsFlooding = true;
newFloodPos.first = vSquareVec[FloodPos.first - num_rows].nPos;
newFloodPos.second = vSquareVec[FloodPos.first - num_rows].nHeight;
qFlooding.push(newFloodPos);
}
break;
case FREE:
if( !vSquareVec[FloodPos.first + 1].bIsVisited &&
!vSquareVec[FloodPos.first + 1].bIsFlooding)
{
vSquareVec[FloodPos.first + 1].bIsFlooding = true;
newFloodPos.first = vSquareVec[FloodPos.first + 1].nPos;
newFloodPos.second = vSquareVec[FloodPos.first + 1].nHeight;
qFlooding.push(newFloodPos);
}
if( !vSquareVec[FloodPos.first - 1].bIsVisited &&
!vSquareVec[FloodPos.first - 1].bIsFlooding)
{
vSquareVec[FloodPos.first - 1].bIsFlooding = true;
newFloodPos.first = vSquareVec[FloodPos.first - 1].nPos;
newFloodPos.second = vSquareVec[FloodPos.first - 1].nHeight;
qFlooding.push(newFloodPos);
}
if( !vSquareVec[FloodPos.first + num_rows].bIsVisited &&
!vSquareVec[FloodPos.first + num_rows].bIsFlooding)
{
vSquareVec[FloodPos.first + num_rows].bIsFlooding = true;
newFloodPos.first = vSquareVec[FloodPos.first + num_rows].nPos;
newFloodPos.second = vSquareVec[FloodPos.first + num_rows].nHeight;
qFlooding.push(newFloodPos);
}
if( !vSquareVec[FloodPos.first - num_rows].bIsVisited &&
!vSquareVec[FloodPos.first - num_rows].bIsFlooding)
{
vSquareVec[FloodPos.first - num_rows].bIsFlooding = true;
newFloodPos.first = vSquareVec[FloodPos.first - num_rows].nPos;
newFloodPos.second = vSquareVec[FloodPos.first - num_rows].nHeight;
qFlooding.push(newFloodPos);
}
nTotalContained += nDepth;
break;
}
}
else
{
vSquareVec[FloodPos.first].bIsFlooding = false;
if( !vSquareVec[FloodPos.first].bIsFenced )
{
vSquareVec[FloodPos.first].bIsFenced = true;
qPerimeter.push(FloodPos);
}
}
}
}
}
return nTotalContained;
}
所有我发现的是顶部,底部,左侧和右侧的正方形高度。
目前,我一直试图弄清楚如何获得总体积,知道如果它们的高度较小,水会溢出到正方形。我越看越多,我认为它应该以递归方式完成,但无法找到实现它的方法。
非常感谢任何帮助。没有找到答案只是为了向正确的方向推进我需要做的事情。
答案 0 :(得分:3)
有趣的问题,有许多不同的解决方案。我今天下午一直在考虑它,我会选择像洪水一样的优先级队列(也许是最小堆)。我们称之为fence
。
您还需要跟踪已访问的项目。最初将所有项目标记为未访问。
首先将网格周边的所有点添加到fence
。
现在你这样循环:
弹出fence
中的前项。您已经选择了周边的最低点之一。
您现在从那时开始进行洪水填充。你可以递归地执行此操作(深度优先),但我将使用无序队列(广度优先)来讨论这个问题。我们将此队列称为flood
。首先将项目推送到flood
。
Flooding就是这样:循环直到flood
...
flood
flood
。fence
即可。您想要有一种方法来判断该项目是否已经在fence
中 - 您不想再次添加它。也许你可以延长你的“访问”标志来应对这一点。就是这样。不可否认,这只是一个思想实验,当我躺在感觉宿醉和肮脏,但我认为这是好的。
正如您所要求的......有些伪代码。
初始设置:
## Clear flags. Note I've added a 'flooding' flag
for each item in map
item.visited <- false # true means item has had its water depth added
item.fenced <- false # true means item is in the fence queue
item.flooding <- false # true means item is in the flooding queue
end
## Set up perimeter
for each item on edge of map (top, left, right, bottom)
push item onto fence
end
waterlevel <- 0
total <- 0
现在是算法的主要部分
while fence has items
item <- pop item from fence
if item.visited = true then loop again
## Update water level
if item.height > waterlevel then waterlevel = item.height
## Flood-fill item using current water level
push item onto flood
item.flooding <- true
while flood has items
item <- pop item from flood
depth <- waterlevel - item.height
if depth >= 0 then
# Item is at or below water level. Add its depth to total.
total <- total + depth
item.visited <- true
# Consider all immediate neighbours of item.
for each neighbour of item
if neighbour.visited = false then
if neighbour.flooding = false then
push neighbour onto flood
neighbour.flooding <- true
end
end
end
else
# Item is above water
item.flooding <- false
if item.fenced = false then
push item onto fence
item.fenced <- true
end
end
end
end
答案 1 :(得分:0)
这不仅仅是计算音量。
根据您发布的示例,您首先测试包含,然后担心容器的容量。
我建议确定电路板中是否有封闭的多边形 如果多边形已关闭,请确定其面积 用于体积计算的高度将是所有边界墙的最小高度 最后,体积将是最小高度乘以多边形的面积。
基于顶点或线段矢量确定闭合多边形的算法的网络研究。
答案 2 :(得分:0)
这有点暴力,但可能会奏效。
您可能会尝试在概念上将电路板分成多个层,例如:
-------------------------
0 | 1 | 1 | 0 | 1 | 1 | 0
1 | 0 |-1 | 1 | 0 | 0 | 1
1 | 1 | 1 | 1 | 1 | 1 | 1
-------------------------
只看最下层。假设-1是底部,则该板看起来像这样:
-------------------------
0 | 0 | 0 | 0 | 0 | 0 | 0
0 | 0 |-1 | 0 | 0 | 0 | 0
0 | 0 | 0 | 0 | 0 | 0 | 0
-------------------------
对于每个方块,确定左侧,右侧,顶部和底部是否存在均值更大的正方形。在这种情况下,我们计算1。
然后移动到下一层,填入最后一层的“洞”。
-------------------------
0 | 1 | 1 | 0 | 1 | 1 | 0
1 | 0 | 0 | 1 | 0 | 0 | 1
1 | 1 | 1 | 1 | 1 | 1 | 1
-------------------------
冲洗,重复。在这一层,我们计算4给我们总共5。
-------------------------
1 | 1 | 1 | 1 | 1 | 1 | 1
1 | 1 | 1 | 1 | 1 | 1 | 1
1 | 1 | 1 | 1 | 1 | 1 | 1
-------------------------
顶层显然没有,我们已经完成了。
在伪代码中:
for each layer l in layers
for each square in l
if there exists a square left, right, top and bottom with higher value
count the square.
修改强>
当然,因为我有一些严重的错误,当我今天早上醒来时,我想到的第一件事就是这个问题,并立即打破我的解决方案。
让我们对示例进行一处更改:
-------------------------
0 | 1 | 1 | 0 | 1 | 1 | 0
1 | 0 |-1 | 1 | 0 | 0 | 1
1 | 1 | 1 | 1 | 1 | 0 | 1
-------------------------
^
向外面打开一个洞。使用当前算法,我们将获得4的解决方案,这显然是错误的。
要解决这个问题,我们需要实现一种反向跟踪算法。
我们不会查看左侧,右侧,顶部和底部的任何位置以获得更高的值,而是检查紧邻的正方形。如果有任何高度相同,我们也需要访问该广场并再次进行检查。如果我们找到通往外面的路,那么原始方块(以及随后所有访问过的方块)都会失败。如果我们遇到死胡同,那么所有访问过的广场都可以计算在内。
通过这种修改,我们可以得到正确的结果。
答案 3 :(得分:0)
这是一段工作代码:基本思想是将电路板水平切割成各级,并确定每个级别可以容纳的音量(复杂度O(x * y * z)):
#include <stdio.h>
#include <memory.h>
// The Cell structure for each level
struct Cell
{
unsigned char height; // either 0 or 1
bool visited; // we only visit the cells that have height of 0
};
// The recursive function that visits a cell, accumulate the water volume (or if leaked due to being at the border, reset the values); it also
// looks to its 4 adjacent cells (if valid) recursively.
// Note that the top level function actually attempts to visit *all* the "connected" cells (and mark them as visited, so they will not be visited again)
// From the top level, the cells are thus visited in "chunks" (as long as they are connected)
void VisitCell(Cell* one_level_cells, unsigned short a_w, unsigned short a_h, unsigned short w, unsigned short h, unsigned __int64* sum, bool* leaked)
{
Cell& cell = one_level_cells[h * a_w + w];
if (cell.height == 0 && !cell.visited)
{
cell.visited = true;
if (w == 0 || w + 1 == a_w || h == 0 || h + 1 == a_h)
{
// I am at the border while I am not guarding the water, the water for this "chunk" is then leaked!
*leaked = true;
*sum = 0;
}
if (!*leaked)
{
// potentially increment the volume, until it's detected leaked at some point
++*sum;
}
if (w < a_w - 1) VisitCell(one_level_cells, a_w, a_h, w+1, h, sum, leaked);
if (w > 0) VisitCell(one_level_cells, a_w, a_h, w-1, h, sum, leaked);
if (h < a_h - 1) VisitCell(one_level_cells, a_w, a_h, w, h+1, sum, leaked);
if (h > 0) VisitCell(one_level_cells, a_w, a_h, w, h-1, sum, leaked);
}
}
//@param int const * const unsigned short *a_board - argument representing the NxM board.
//@param unsigned short a_w - argument representing the width of the board
//@param unsigned short a_h - argument representing the height of the board
//@return - unsigned __int64 - the volume of water the board retains
// complexity: O(a_w * a_h * max_height)
unsigned __int64 CalculateVolume(const unsigned short *a_board, unsigned short a_w, unsigned short a_h)
{
if (!a_board || a_w < 3 || a_h < 3)
{
return 0;
}
// Basic algorithm: slice the board horizontally into as many levels as the maximum height of the board
// for each sliced level, determine the water volume cubed so far, and the total volume is the sum of the volume of the individual level
unsigned __int32 n = a_w * a_h;
unsigned short max_height = 0;
for (unsigned __int32 i = 0; i < n; ++i)
{
if (max_height < a_board[i])
{
max_height = a_board[i];
}
}
unsigned short *board = new unsigned short[n];
memcpy(board, a_board, n * sizeof(unsigned short));
Cell* one_level_cells = new Cell[n];
unsigned __int64 total_volume = 0;
for (unsigned short i = 0; i < max_height; ++i)
{
// form a new current level of cells (and update the copy of the board accordingly)
unsigned __int64 volume_this_level = 0;
for (unsigned __int32 j = 0; j < n; ++j)
{
if (board[j] > 0)
{
--board[j];
one_level_cells[j].height = 1;
}
else
{
one_level_cells[j].height = 0;
}
one_level_cells[j].visited = false;
}
// visit all the cells within the current level
// we mark the cells after being visited, and the cells are visited in "chunks" when they are "connected" together
// so effectively, most of the top level cell visiting would return immediately, rather than trying to revisit the cells again and again
for (unsigned short h = 0; h < a_h; ++h)
{
for (unsigned short w = 0; w < a_w; ++w)
{
unsigned __int64 sum = 0;
bool leaked = false;
// NB: the top level function here will attempt to cover *all* the connected cells at the current level (in the recursion)
// so even though we are still iterating through all the cells at the top level, most of them should find that the cell has been visited
// so the sum here is actually a "chunked" sum in the perception of the top level cells
VisitCell(one_level_cells, a_w, a_h, w, h, &sum, &leaked);
volume_this_level += sum;
}
}
total_volume += volume_this_level;
}
delete[] one_level_cells;
delete[] board;
return total_volume;
}
int main()
{
// feel free to play with this board
unsigned short board[] = {
2, 2, 2, 2, 2, 2, 2, 2,
2, 1, 1, 1, 1, 1, 1, 2,
2, 1, 2, 3, 3, 2, 1, 2,
2, 1, 3, 1, 1, 3, 1, 2,
2, 1, 3, 1, 1, 3, 1, 2,
2, 1, 2, 3, 3, 2, 1, 2,
2, 1, 1, 1, 1, 1, 1, 2,
2, 2, 2, 2, 2, 2, 2, 2,
};
printf("Volume: %lld\n", CalculateVolume(board, 8, 8));
return 0;
}
答案 4 :(得分:0)
这是@paddy的伪代码的python(2.7)版本。希望这对某人有帮助。
import heapq
block =[
1, 2, 3,
4 ,2,6,
7, 0,5,
11,15, 13,
14,15,16,
1,0,1,
1,1,1]
cmax =3;
rmax =7;
items =[]
fence = []
flood = []
waterlevel = 0
total = 0
class Item(object):
visited = False
fenced = False
flooding = False
height= 0
index = 0
i=0
## initializing blocks
for val in block:
item = Item();
item.height = val
item.index = i
i+=1
items.append((item.height,item))
## find out the edges
for i in range (cmax):
heapq.heappush(fence, items[i])
heapq.heappush(fence, items[i+(rmax-1)*cmax])
print items[i][1].height,items[i+(rmax-1)*cmax][1].height
for i in range(1,rmax-1):
heapq.heappush(fence, items[cmax*i])
heapq.heappush(fence, items[cmax*i+(cmax-1)])
print items[cmax*i][1].height,items[cmax*i+(cmax-1)][1].height
## get neighbour
def get_neighbour(i):
c= i%cmax
r= i//cmax
neighbour = []
if (c != 0):
neighbour.append(items[r*cmax+c-1])
if (c != (cmax -1)):
neighbour.append(items[r*cmax+c+1])
if (r != 0):
neighbour.append(items[(r-1)*cmax+c])
if (r != (rmax -1)):
neighbour.append(items[(r+1)*cmax+c])
return neighbour
while (len(fence)>0):
item = heapq.heappop(fence)
if(item[1].visited):
continue
if (item[1].height > waterlevel):
waterlevel = item[1].height
heapq.heappush(flood,item)
item[1].flooding = True
while(len(flood)>0):
fitem = heapq.heappop(flood)
depth = waterlevel - fitem[1].height
if (depth >= 0):
total += depth
fitem[1].visited = True
neighbour = get_neighbour(fitem[1].index)
for nitem in neighbour:
if nitem[1].visited == False :
if nitem[1].flooding == False :
heapq.heappush(flood,nitem)
nitem[1].flooding = True
else:
fitem[1].flooding = False
if fitem[1].fenced == False:
heapq.heappush(fence,fitem)
fitem[1].fenced = True
print total