C++ 防洪-洪水填充还是有更好的方法?
我在做练习和提高技能的任务,但我很难解决这个问题: 你有一张w*h大小的地图。这张地图的每个盒子上都有wallflood 保护还是什么都没有。水可以朝八个方向流动 在地图边缘的每个框上。当然,水不能泛滥 用于防洪的箱子。你会得到地图的大小, 墙的数量和每面墙的位置 开始时,地图是空的。您的任务是在放置每个 这堵墙告诉我们有多大的区域可以防水 所以,我有代码可以工作。但是太慢了。限制为:地图的大小w和h 1≤w、 h≤2000 墙数:n 1≤N≤w×h 我尝试了8路泛光填充算法,然后将其改进为8路扫描线填充。它太慢了,有一半的测试条目没有时间了。如果你愿意,我会发布我的代码。 所以我的问题是:如何改进我的算法,使其更快?还是我选择的算法完全错了,还有更好的方法?谢谢你的建议 测试条目:C++ 防洪-洪水填充还是有更好的方法?,c++,algorithm,optimization,flood-fill,C++,Algorithm,Optimization,Flood Fill,我在做练习和提高技能的任务,但我很难解决这个问题: 你有一张w*h大小的地图。这张地图的每个盒子上都有wallflood 保护还是什么都没有。水可以朝八个方向流动 在地图边缘的每个框上。当然,水不能泛滥 用于防洪的箱子。你会得到地图的大小, 墙的数量和每面墙的位置 开始时,地图是空的。您的任务是在放置每个 这堵墙告诉我们有多大的区域可以防水 所以,我有代码可以工作。但是太慢了。限制为:地图的大小w和h 1≤w、 h≤2000 墙数:n 1≤N≤w×h 我尝试了8路泛光填充算法,然后将其改进为8路
Input:
4 4 //size w and h
10 // number of walls
1 1 //position of wall - first x, second y coordinate;
1 2
1 3
2 1
2 3
3 1
3 2
3 3
2 2
3 4
Output:
1 //how big are is covered against flood
2
3
4
5
6
7
9
9
10
示例输入说明:洪水墙的前8部分
保护区域大小为3 x 3。第九部分完全没有作用,
因为盒子2,2已经被保护了。第十部分是
不缔结任何领土,因此只贡献其领土
只出现了1个
我的代码:
#include<iostream>
using namespace std;
int **ostrov;
int area;
#define stackSize 16777216
int stack[stackSize];
int stackPointer;
int h, w;
bool pop(int
&x, int &y)
{
if (stackPointer > 0)
{
int p = stack[stackPointer];
x = p / h;
y = p % h;
stackPointer--;
return 1;
}
else
{
return 0;
}
}
bool push(int x, int y)
{
if (stackPointer < stackSize - 1)
{
stackPointer++;
stack[stackPointer] = h * x + y;
return 1;
}
else
{
return 0;
}
}
void emptyStack()
{
int x, y;
while (pop(x, y));
}
//The scanline floodfill algorithm using our own stack routines, faster
void floodFillScanlineStack(int x, int y, int newColor, int oldColor)
{
if (oldColor == newColor) return;
emptyStack();
int y1;
bool spanLeft, spanRight, spanDDLeft, spanDDRight, spanDULeft, spanDURight;
if (!push(x, y)) return;
while (pop(x, y))
{
y1 = y;
while (y1 >= 0 &&ostrov[x][y1] == oldColor) y1--;
y1++;
spanLeft = spanRight = spanDDLeft = spanDDRight = spanDULeft = spanDURight = 0;
while (y1 < h && ostrov[x][y1] == oldColor)
{
if (ostrov[x][y1] == oldColor)
pocet++;
ostrov[x][y1] = newColor;
if (!spanLeft && x > 0 && ostrov[x - 1][y1] == oldColor)
{
if (!push(x - 1, y1)) return;
spanLeft = 1;
}
else if (spanLeft && x > 0 && ostrov[x - 1][y1] != oldColor)
{
spanLeft = 0;
}
if (!spanRight && x < w - 1 && ostrov[x + 1][y1] == oldColor)
{
if (!push(x + 1, y1)) return;
spanRight = 1;
}
else if (spanRight && x < w - 1 && ostrov[x + 1][y1] != oldColor)
{
spanRight = 0;
}
if (!spanDDLeft && x > 0 && y1 + 1 < h && ostrov[x - 1][y1 + 1] == oldColor)
{
if (!push(x - 1, y1 + 1)) return;
spanDDLeft = 1;
}
else if (spanDDLeft && x > 0 && y1 + 1 < h && ostrov[x - 1][y1 + 1] != oldColor)
{
spanDDLeft = 0;
}
if (!spanDDRight && x + 1 < w && y1 + 1 < h && ostrov[x + 1][y1 + 1] == oldColor)
{
if (!push(x + 1, y1 + 1)) return;
spanDDRight = 1;
}
else if (spanDDRight && x + 1 < w && y1 + 1 < h && ostrov[x + 1][y1 + 1] != oldColor)
{
spanDDRight = 0;
}
if (!spanDULeft && x > 0 && y1 > 0 && ostrov[x - 1][y1 - 1] == oldColor)
{
if (!push(x - 1, y1 - 1)) return;
spanDULeft = 1;
}
else if (spanDULeft && x > 0 && y1 > 0 && ostrov[x - 1][y1 - 1] != oldColor)
{
spanDULeft = 0;
}
if (!spanDURight && x + 1 < w && y1 > 0 && ostrov[x + 1][y1 - 1] == oldColor)
{
if (!push(x + 1, y1 - 1)) return;
spanDURight = 1;
}
else if (spanDURight && x + 1 < w && y1 > 0 && ostrov[x + 1][y1 - 1] != oldColor)
{
spanDURight = 0;
}
y1++;
}
}
}
int main()
{
cin >> h >> w;
h += 2;
w += 2;
ostrov = new int*[w];
for (int i = 0; i < w; i++) {
ostrov[i] = new int[h];
for (int j = 0; j < h; j++)
ostrov[i][j] = 1;
}
int n;
cin >> n;
int color = 1;
int act = 0; //actual color
int prev = 0; //last color
for (int i = 0; i < n; i++) {
color++;
suc = color % 2;
prev = (color - 1) % 2;
int x, y;
cin >> x >> y;
if (ostrov[y][x] == act) {
cout << (w * h) - area << endl;
color--;
continue;
}
area = 0;
ostrov[y][x] = 5;
floodFillScanlineStack(0, 0, act, prev);
cout << (w * h) - area << endl;
}
}
编辑:
现在我意识到这个封闭区域不需要是矩形或正方形,它可以是多边形。此外,地图中可能会有更多的多边形。在我得到部分墙的坐标后,我必须告诉你:
1.如果它是一个封闭的区域——如果是的话,在我必须添加到封闭的区域之前,没有封闭的区域有多大;
2.如果它没有形成一些多边形,并且它不在已经封闭的区域内,则添加到封闭区域编号1,因为此地图框中的水不会泛滥;
3.如果它位于已封闭的区域内,请不要添加任何内容,因为它不会再封闭任何区域。这里有一个想法可能会有所帮助。封闭比墙本身占用的空间更多的唯一方法是创建某种封闭路径。考虑在一个新的墙段被放置的地方开始执行4路洪水填充。它只需稍加修改,就可以让您检测到一条封闭的路径,并提醒您注意,有一些非墙壁空间是安全的,不会被洪水淹没 事实上,这可能是一种深度优先的搜索方式,您可以在其中查找第二次出现的原始点。您需要继续搜索,因为一个新的墙段可能会完成许多闭合路径,实际上,这可能不是真的;为了防止8向洪水泛滥,最后需要的一块墙将只属于一个新形成的环,除非您将其放置在其他已形成的形状内 一旦你检测到一个闭合环,你只需要用其他颜色填充内部正方形,如果白色是空白,黑色是墙壁,可能是红色或其他什么;红色广场上的任何未来墙都不会有帮助。弄清楚如何填充内部是现在唯一的问题——这是一个简单的问题。只需检查新墙周围的方格。一旦你找到一个正方形,根据你的方向水平或垂直扫描,看你是否再次穿过这条路径。如果你穿过奇数次,你就在形状里面;如果偶数次,你就在外面。新墙板周围将有一些空白,以完成闭合路径,否则,任何循环都必须已经闭合
呸。我认为这应该比每次迭代时的洪水填充速度快得多。仍然不是在公园散步,而是一些值得思考的东西。嗯,您没有提供代码,因此无法提供帮助。此外,这听起来似乎更适合@Let_Me_Be,除了主题中最重要的一个标准,就是要审查的代码必须包含在问题中。我不认为这更适合codereview,因为我想知道如何比使用Floodfill更快地解决任务,不检讨我的code@JozefBugoš你在哪里找到这个问题?如果边界是一道屏障,洪水从0,0开始,你不能在1,0,0,1和1,1处用三堵墙隔离0,0,并防止洪水淹没地图的剩余Ow*h吗?如果你只有两个或更少的墙可以放置,你不能阻止任何非墙区域被淹没。谢谢!我会看一看,试试看。我会注意到你的。@Patrik87我在考虑你的想法,我的结论是,检测周期的原始DFS由于一个原因无法工作,它只检测一个周期,而可能有更长的周期-我需要最长的周期。如果我找到了,我会检查禁区和f在哪里 我会用我的洪水填充算法,但我需要最长的周期。我发现了这个,但我不理解Alex Kemper给出的代码。你能给我解释一下,还是把它重写到C++?另外,我只需要检查一个顶点的循环