使用按位运算填充洪水

时间:2014-01-31 00:43:05

标签: c++ c bit-manipulation bitwise-operators

我有一个位图存储为(固定)无符号整数,例如:

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

1 个答案:

答案 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;
}