我有一个位图存储为(固定)无符号整数,例如:
1 0 0 1
1 0 1 0
1 1 0 1
0 1 1 0
...存储为整数数组[ 9, 10, 13, 6 ]
(自上而下,左侧最高位)。
我想实现泛洪填充算法。例如,如果m
是上面描述的地图,floodFill(m, 3, 2)
应生成地图:
1 0 0 0
1 0 0 0
1 1 0 0
0 1 1 0
(这里,3,2
对应第三行(0索引),第二列(右起)。答案将编码为[ 8, 8, 12, 6 ]
。)
我当然可以实现其中一种标准方法,但我想知道我是否可以使用位操作技巧做得更好。
例如,如果解决方案的一部分包含在地图m0
中,我认为我m0 | ((m0 >> 1) & m)
“增加”了右边的洪水填充。
这是在位图上并行填充洪水的标准技巧吗?任何人都可以提出完整的算法吗?证明有关运行时间的有趣界限?
编辑:其他一些例子:
floodFill ( 0 0 1 1 , 1, 1 ) = 0 0 1 1
1 1 1 0 1 1 1 0
0 0 1 1 0 0 1 1
1 1 0 1 0 0 0 1
floodFill ( 1 0 0 1 , 1, 2 ) = 0 0 0 0
0 1 0 0 0 1 0 0
0 1 0 1 0 1 0 0
0 0 1 1 0 0 0 0
答案 0 :(得分:2)
以下作品:
std::vector<unsigned> floodFill(const std::vector<unsigned>& map, unsigned int row, unsigned int column)
{
std::vector<unsigned> res(map.size() + 2); // Add 'border' to avoid special case
res[1 + row] = (1u << column) & map[row]; // Seed point (column: right to left)
std::vector<unsigned> last;
do {
last = res;
for (std::size_t i = 0, size = map.size(); i != size; ++i) {
res[i + 1] |= (res[i] | res[i + 2] | (res[i + 1] << 1u) | (res[i + 1] >> 1u)) & map[i];
}
} while (last != res);
res.pop_back(); // remove extra border.
res.erase(res.begin()); // remove extra border.
return res;
}
测试它:(我在这里使用C ++ 11)
int main(int argc, char *argv[])
{
const std::vector<unsigned int> v = {9, 10, 13, 6};
const std::vector<unsigned int> expected = {8, 8, 12, 6};
std::vector<unsigned int> res = floodFill(v, 3, 2);
assert(res == expected);
assert(floodFill({3, 14, 3, 13}, 1, 1) == std::vector<unsigned int>({3, 14, 3, 1}));
assert(floodFill({9, 4, 5, 3}, 1, 2) == std::vector<unsigned int>({0, 4, 4, 0}));
return 0;
}