如何检查网格中的点是垂直/水平连接的? (1彼此远离)

时间:2017-10-19 02:40:35

标签: c++

让我们只使用1作为有一个点,如果没有则使用0。

例如,网格:

0 0 0 0 0

1 1 1 1 1

0 0 0 0 0

1 1 1 1 1

不会连接在一起,而

0 0 1 0 0

0 1 1 0 0

0 0 1 1 0

0 0 0 1 1

我觉得好像使用像BFS这样的东西对于一些可能相当简单的东西来说效率非常低;还有其他选择吗?

2 个答案:

答案 0 :(得分:1)

BFS或DFS确实是正确的解决方案。其余的只是利用直线网格(栅格)的特性以更有效的方式实现这种搜索算法,优选地比“直接”实现更有效。例如,某些经典的4向栅格scanline flood-fill algorithm是搜索网格中连接组件的好方法(请参阅“扫描线填充”部分)。

答案 1 :(得分:1)

这类问题的最佳渐近复杂性来自使用秩和路径压缩的并集查找算法。

Union查找每个新点与一个组名称相关联,该组名称是唯一的,取自左侧或顶级邻居,或统一组(通过建立从一个组到另一个组的链接)。 / p>

最后,所有最初唯一群组的所有父母都指向相同的项目,在这种情况下,该集合已连接。

Further reading with c++ source code

Further reading for image processing

#include "catch.hpp"
#include <vector>
template <typename T>
T parent(std::vector<T> &links, T item)
{
    if (item == 0)
        return item;
    while (links[(size_t)item - 1] != item)
        item = links[(size_t)item - 1];
    // Should implement path compression
    return item;
}

template <typename T, int N, int M>
bool is_connected(T(&array)[N][M])
{
    // Assumption is that the type T is large enough to hold N*M/2 distinct entries
    // Thus we can use/modify the array itself to record (roots) of distinct labels
    // Of course we could copy the array into a vector of type size_t
    std::vector<T> parents;

    for (auto j = 0; j < N; j++)
    {
        for (auto i = 0; i < M; i++)
        {
            T &current = array[j][i];
            if (!current)
                continue;
            T left = i ? parent(parents, array[j][i - 1]) : 0;
            T above = j ? parent(parents, array[j - 1][i]) : 0;
            if (left == 0)
            {
                if (above)
                    current = above;
                else
                    parents.emplace_back(current = (T)(parents.size() + 1));
            }
            else
            {
                // Todo: implement rank based selection of joining the sets
                current = left;
                if (above != 0 && above != left)
                    parents[(size_t)above - 1] = left;
            }
        }
    }

    // Check that all intermediate disjoint sets have now a single root
    if (parents.size() == 0)
        return false;   // is empty set connected or not?

    auto last_item = parents.back();
    auto root = parent(parents, last_item);
    parents.pop_back();
    for (auto &group : parents)
    {
        if (root != parent(parents, group))
            return false;
    }
    return true;
}

SCENARIO("Is connected")
{
    int arr[4][4] = {
        { 1, 0, 1, 0 },
        { 1, 0, 1, 0 },
        { 1, 0, 1, 0 },
        { 1, 1, 1, 1 }
    };
    auto foo = is_connected(arr);
    CHECK(foo == true);
    arr[3][1] = 0;
    CHECK(is_connected(arr) == false);
}