车削不同颜色的2D阵列成单一颜色最优 [英] Turning a 2D array of different color into a single color optimally

查看:111
本文介绍了车削不同颜色的2D阵列成单一颜色最优的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图找到益智游戏投它的​​解决方案。其主要思想是把k个不同颜色的整体N * M的游戏板成一个单一的颜色。我必须从板的左上角开始,把相同颜色的块到相邻节点的颜色,从而前进,最后整板涌入单一颜色之一。例如:

I am trying to find a solution of the puzzle game 'Flood It'. The main idea is to turn a whole N*M game board of k different colors into a single color. I have to start from the top left corner of the board and turn the same colored block into one of the colors of neighboring nodes and thus moving ahead and flooding the whole board into a single color at last. For example:

Initial Board:
 1 1 1 2 2 3
 1 1 2 3 4 5
 1 1 1 1 3 4
 1 4 3 2 1 5
 2 3 4 5 1 2

Final Board:
 1 1 1 1 1 1
 1 1 1 1 1 1
 1 1 1 1 1 1
 1 1 1 1 1 1
 1 1 1 1 1 1

,其中1,2,3,4,5再presents不同的颜色。我有prepared一个C ++ code在董事会的任何位置上找出相同颜色的块的区域。这可以在第一左上角的单元格被应用,然后在它的相邻节点充斥颜色。我的code是如下:

where 1,2,3,4,5 represents different colors. I have prepared a C++ code for finding out the area of same colored block at any position of the board . This can be applied at the top left cell at first and then at the neighboring nodes of it to flood the color. My code is as follows:

#include <cstdint>
#include <vector>
#include <queue>
#include <string>
#include <iostream>

typedef std::vector<int32_t> vec_1d;
typedef std::vector<vec_1d> vec_2d;

// Print the 2d vector with a label
void dump(std::string const& label, vec_2d const& v)
{
    std::cout << label << "\n";
    for (std::size_t y(0); y < v.size(); ++y) {
        for (std::size_t x(0); x < v[0].size(); ++x) {
            std::cout << v[y][x] << " ";
        }
        std::cout << "\n";
    }
    std::cout << "\n";
}

// Recursive implementation of the search
void find_connected_r(int32_t target_color
, std::size_t x
, std::size_t y
, vec_2d const& colors
, vec_2d& result)
{
    if ((result[y][x] == 1) || (colors[y][x] != target_color)) {
        return;
    }

    result[y][x] = 1;

    std::size_t width(colors[0].size());
    std::size_t height(colors.size());

    if (x > 0) {
        find_connected_r(target_color, x - 1, y, colors, result);
    }
    if (y > 0) {
        find_connected_r(target_color, x, y - 1, colors, result);
    }
    if (x < (width - 1)) {
        find_connected_r(target_color, x + 1, y, colors, result);
    }
    if (y < (height - 1)) {
        find_connected_r(target_color, x, y + 1, colors, result);
    }
}


// Entry point to the search, select the implementation with last param
vec_2d find_connected(std::size_t x, std::size_t y, vec_2d const& colors,    bool recursive)
{
   if (colors.empty() || colors[0].empty()) {
       throw std::runtime_error("Invalid input array size");
   }

   int32_t target_color(colors[y][x]);

    vec_2d result(colors.size(), vec_1d(colors[0].size(), 0));

    if (recursive) {
        find_connected_r(target_color, x, y, colors, result);
    }
    else {
        find_connected(target_color, x, y, colors, result);
    }

    return result;
}

void dump_coordinates(std::string const& label, vec_2d const& v)
{
    std::cout << label << "\n";
    for (std::size_t y(0); y < v.size(); ++y) {
        for (std::size_t x(0); x < v[0].size(); ++x) {
            if (v[y][x]) {
                std::cout << "(" << x << ", " << y << ") ";
            }
        }
    }
    std::cout << "\n";
}

int main()
{
    vec_2d colors{
        { 1, 1, 1, 1, 1, 1 }
    , { 2, 2, 2, 3, 3, 1 }
    , { 1, 1, 1, 1, 3, 1 }
    , { 1, 3, 3, 3, 3, 1 }
    , { 1, 1, 1, 1, 1, 1 }
    };
}

我将

如何把整个板/矩阵成一个单一的颜色通过检查相邻节点?

How will I turn the whole board/matrix into a single color by examining the neighboring nodes?

推荐答案

一个可能的顶层算法来解决这个难题是重复以下,直到有对整板只有一种颜色:

A possible top-level algorithm to solve this puzzle is to repeat the following until there is only one color on the whole board:


  • 找到所有连续颜色区域。对待在(0,0),该地区小学,所有其他作为辅助。

  • 用一种颜色的主要区域的颜色不同的选择最大的(由砖数)二级区域。让我们称这个二级区域的颜色在对new_color

  • 重新着色的主要地区对new_color。

我们应该保持的 cumulative_mask 要跟踪那些已经确定了一些区域的一部分,所有的瓷砖。

We should keep a cumulative_mask to track of all the tiles that are already identified as part of some region.

首先,我们发现的主要区域,在(0,0)开始搜索,并更新我们的结果cumulative_mask。

First we find the primary region, starting search at (0,0), and update our cumulative_mask with the result.

然后重复,直到没有更多的地区可以发现:

Then repeat until no more regions can be found:


  • 找到的第一个零平铺在cumulative_mask,它具有在主区域掩模的至少一个非零块的位置。

  • 找到该地区开始在这个位置。

  • 更新与本地区的面具cumulative_mask。

只需通过二级区域迭代,并找到具有最大计数,其具有不同的颜色比主区域的区域。

Simply iterate through secondary regions, and find the region with largest count, which has a different color than the primary region.

(也 coliru

注:故意编写方式,使之可以理解的算法。这绝对可以重构,并且它缺少了很多错误检查。

Note: Intentionally written in a way to make it possible to understand the algorithm. This could definitely be refactored, and it's missing a lot of error checking.

#include <cstdint>
#include <vector>
#include <queue>
#include <string>
#include <iostream>

typedef std::vector<int32_t> vec_1d;
typedef std::vector<vec_1d> vec_2d;

typedef std::pair<std::size_t, std::size_t> position;

position const INVALID_POSITION(-1, -1);
int32_t const INVALID_COLOR(0);

// ============================================================================

struct region_info
{
    int32_t color;
    vec_2d mask;

    std::size_t count() const
    {
        std::size_t result(0);
        for (std::size_t y(0); y < mask.size(); ++y) {
            for (std::size_t x(0); x < mask[0].size(); ++x) {
                if (mask[y][x]) {
                    ++result;
                }
            }
        }
        return result;
    }
};

struct region_set
{
    // The region that contains (0, 0)
    region_info primary;

    // All other regions
    std::vector<region_info> secondary;
};

// ============================================================================

// Print the 2D vector with a label
void dump(std::string const& label, vec_2d const& v)
{
    std::cout << label << "\n";
    for (std::size_t y(0); y < v.size(); ++y) {
        for (std::size_t x(0); x < v[0].size(); ++x) {
            std::cout << v[y][x] << " ";
        }
        std::cout << "\n";
    }
    std::cout << "\n";
}

// Print the coordinates of non-zero elements of 2D vector with a label
void dump_coordinates(std::string const& label, vec_2d const& v)
{
    std::cout << label << "\n";
    for (std::size_t y(0); y < v.size(); ++y) {
        for (std::size_t x(0); x < v[0].size(); ++x) {
            if (v[y][x]) {
                std::cout << "(" << x << ", " << y << ") ";
            }
        }
    }
    std::cout << "\n";
}

void dump(region_info const& ri)
{
    std::cout << "Region color: " << ri.color << "\n";
    std::cout << "Region count: " << ri.count() << "\n";
    dump("Region mask:", ri.mask);
}

void dump(region_set const& rs)
{
    std::cout << "Primary Region\n" << "\n";
    dump(rs.primary);

    for (std::size_t i(0); i < rs.secondary.size(); ++i) {
        std::cout << "Secondary Region #" << i << "\n";
        dump(rs.secondary[i]);
    }
}

// ============================================================================

// Find connected tiles - implementation
void find_connected(int32_t target_color
    , std::size_t x
    , std::size_t y
    , vec_2d const& colors
    , vec_2d& result)
{
    std::size_t width(colors[0].size());
    std::size_t height(colors.size());

    std::queue<position> s;

    s.push(position(x, y));

    while (!s.empty()) {
        position pos(s.front());
        s.pop();

        if (result[pos.second][pos.first] == 1) {
            continue;
        }
        if (colors[pos.second][pos.first] != target_color) {
            continue;
        }
        result[pos.second][pos.first] = 1;

        if (pos.first > 0) {
            s.push(position(pos.first - 1, pos.second));
        }
        if (pos.second > 0) {
            s.push(position(pos.first, pos.second - 1));
        }
        if (pos.first < (width - 1)) {
            s.push(position(pos.first + 1, pos.second));
        }
        if (pos.second < (height - 1)) {
            s.push(position(pos.first, pos.second + 1));
        }
    }
}

// Find connected tiles - convenience wrapper
vec_2d find_connected(std::size_t x, std::size_t y, vec_2d const& colors)
{
    if (colors.empty() || colors[0].empty()) {
        throw std::runtime_error("Invalid input array size");
    }

    int32_t target_color(colors[y][x]);

    vec_2d result(colors.size(), vec_1d(colors[0].size(), 0));

    find_connected(target_color, x, y, colors, result);

    return result;
}

// ============================================================================

// Change color of elements at positions with non-zero mask value to new color
vec_2d& change_masked(int32_t new_color
    , vec_2d& colors
    , vec_2d const& mask)
{
    for (std::size_t y(0); y < mask.size(); ++y) {
        for (std::size_t x(0); x < mask[0].size(); ++x) {
            if (mask[y][x]) {
                colors[y][x] = new_color;
            }
        }
    }

    return colors;
}

// Combine two masks
vec_2d combine(vec_2d const& v1, vec_2d const& v2)
{
    vec_2d result(v1);

    for (std::size_t y(0); y < v2.size(); ++y) {
        for (std::size_t x(0); x < v2[0].size(); ++x) {
            if (v2[y][x]) {
                result[y][x] = v2[y][x];
            }
        }
    }

    return result;
}

// Find position of first zero element in mask
position find_first_zero(vec_2d const& mask)
{
    for (std::size_t y(0); y < mask.size(); ++y) {
        for (std::size_t x(0); x < mask[0].size(); ++x) {
            if (!mask[y][x]) {
                return position(x, y);
            }
        }
    }
    return INVALID_POSITION;
}

bool has_nonzero_neighbor(std::size_t x, std::size_t y, vec_2d const& mask)
{
    bool result(false);
    if (x > 0) {
        result |= (mask[y][x - 1] != 0);
    }
    if (y > 0) {
        result |= (mask[y - 1][x] != 0);
    }
    if (x < (mask[0].size() - 1)) {
        result |= (mask[y][x + 1] != 0);
    }
    if (y < (mask.size() - 1)) {
        result |= (mask[y + 1][x] != 0);
    }
    return result;
}

// Find position of first zero element in mask
// which neighbors at least one non-zero element in primary mask
position find_first_zero_neighbor(vec_2d const& mask, vec_2d const& primary_mask)
{
    for (std::size_t y(0); y < mask.size(); ++y) {
        for (std::size_t x(0); x < mask[0].size(); ++x) {
            if (!mask[y][x]) {
                if (has_nonzero_neighbor(x, y, primary_mask)) {
                    return position(x, y);
                }
            }
        }
    }
    return INVALID_POSITION;
}

// ============================================================================

// Find all contiguous color regions in the image
// The region starting at (0,0) is considered the primary region
// All other regions are secondary
// If parameter 'only_neighbors' is true, search only for regions
// adjacent to primary region, otherwise search the entire board
region_set find_all_regions(vec_2d const& colors, bool only_neighbors = false)
{
    region_set result;

    result.primary.color = colors[0][0];
    result.primary.mask = find_connected(0, 0, colors);

    vec_2d cumulative_mask = result.primary.mask;

    for (;;) {
        position pos;
        if (only_neighbors) {
            pos = find_first_zero_neighbor(cumulative_mask, result.primary.mask);
        } else {
            pos = find_first_zero(cumulative_mask);
        }

        if (pos == INVALID_POSITION) {
            break; // No unsearched tiles left
        }

        region_info reg;
        reg.color = colors[pos.second][pos.first];
        reg.mask = find_connected(pos.first, pos.second, colors);

        cumulative_mask = combine(cumulative_mask, reg.mask);

        result.secondary.push_back(reg);
    }

    return result;
}

// ============================================================================

// Select the color to recolor the primary region with
// based on the color of the largest secondary region of non-primary color
int32_t select_color(region_set const& rs)
{
    int32_t selected_color(INVALID_COLOR);
    std::size_t selected_count(0);

    for (auto const& ri : rs.secondary) {
        if (ri.color != rs.primary.color) {
            if (ri.count() > selected_count) {
                selected_count = ri.count();
                selected_color = ri.color;
            }
        }
    }

    return selected_color;
}

// ============================================================================

// Solve the puzzle
// If parameter 'only_neighbors' is true, search only for regions
// adjacent to primary region, otherwise search the entire board
// Returns the list of selected colors representing the solution steps
vec_1d solve(vec_2d colors, bool only_neighbors = false)
{
    vec_1d selected_colors;

    for (int32_t i(0);; ++i) {
        std::cout << "Step #" << i << "\n";
        dump("Game board: ", colors);

        region_set rs(find_all_regions(colors, true));

        dump(rs);

        int32_t new_color(select_color(rs));
        if (new_color == INVALID_COLOR) {
            break;
        }

        std::cout << "Selected color: " << new_color << "\n";
        selected_colors.push_back(new_color);

        change_masked(new_color, colors, rs.primary.mask);

        std::cout << "\n------------------------------------\n\n";
    }

    return selected_colors;
}

// ============================================================================

int main()
{
    vec_2d colors{
        { 1, 1, 1, 1, 1, 1 }
        , { 2, 2, 2, 3, 3, 1 }
        , { 1, 1, 4, 5, 3, 1 }
        , { 1, 3, 3, 4, 3, 1 }
        , { 1, 1, 1, 1, 1, 1 }
    };

    vec_1d steps(solve(colors, true));

    std::cout << "Solved in " << steps.size() << " step(s):\n";
    for (auto step : steps) {
        std::cout << step << " ";
    }
    std::cout << "\n\n";
}

// ============================================================================

该程序的输出:

Step #0
Game board: 
1 1 1 1 1 1 
2 2 2 3 3 1 
1 1 4 5 3 1 
1 3 3 4 3 1 
1 1 1 1 1 1 

Primary Region

Region color: 1
Region count: 18
Region mask:
1 1 1 1 1 1 
0 0 0 0 0 1 
1 1 0 0 0 1 
1 0 0 0 0 1 
1 1 1 1 1 1 

Secondary Region #0
Region color: 2
Region count: 3
Region mask:
0 0 0 0 0 0 
1 1 1 0 0 0 
0 0 0 0 0 0 
0 0 0 0 0 0 
0 0 0 0 0 0 

Secondary Region #1
Region color: 3
Region count: 4
Region mask:
0 0 0 0 0 0 
0 0 0 1 1 0 
0 0 0 0 1 0 
0 0 0 0 1 0 
0 0 0 0 0 0 

Secondary Region #2
Region color: 4
Region count: 1
Region mask:
0 0 0 0 0 0 
0 0 0 0 0 0 
0 0 1 0 0 0 
0 0 0 0 0 0 
0 0 0 0 0 0 

Secondary Region #3
Region color: 3
Region count: 2
Region mask:
0 0 0 0 0 0 
0 0 0 0 0 0 
0 0 0 0 0 0 
0 1 1 0 0 0 
0 0 0 0 0 0 

Secondary Region #4
Region color: 4
Region count: 1
Region mask:
0 0 0 0 0 0 
0 0 0 0 0 0 
0 0 0 0 0 0 
0 0 0 1 0 0 
0 0 0 0 0 0 

Selected color: 3

------------------------------------

Step #1
Game board: 
3 3 3 3 3 3 
2 2 2 3 3 3 
3 3 4 5 3 3 
3 3 3 4 3 3 
3 3 3 3 3 3 

Primary Region

Region color: 3
Region count: 24
Region mask:
1 1 1 1 1 1 
0 0 0 1 1 1 
1 1 0 0 1 1 
1 1 1 0 1 1 
1 1 1 1 1 1 

Secondary Region #0
Region color: 2
Region count: 3
Region mask:
0 0 0 0 0 0 
1 1 1 0 0 0 
0 0 0 0 0 0 
0 0 0 0 0 0 
0 0 0 0 0 0 

Secondary Region #1
Region color: 4
Region count: 1
Region mask:
0 0 0 0 0 0 
0 0 0 0 0 0 
0 0 1 0 0 0 
0 0 0 0 0 0 
0 0 0 0 0 0 

Secondary Region #2
Region color: 5
Region count: 1
Region mask:
0 0 0 0 0 0 
0 0 0 0 0 0 
0 0 0 1 0 0 
0 0 0 0 0 0 
0 0 0 0 0 0 

Secondary Region #3
Region color: 4
Region count: 1
Region mask:
0 0 0 0 0 0 
0 0 0 0 0 0 
0 0 0 0 0 0 
0 0 0 1 0 0 
0 0 0 0 0 0 

Selected color: 2

------------------------------------

Step #2
Game board: 
2 2 2 2 2 2 
2 2 2 2 2 2 
2 2 4 5 2 2 
2 2 2 4 2 2 
2 2 2 2 2 2 

Primary Region

Region color: 2
Region count: 27
Region mask:
1 1 1 1 1 1 
1 1 1 1 1 1 
1 1 0 0 1 1 
1 1 1 0 1 1 
1 1 1 1 1 1 

Secondary Region #0
Region color: 4
Region count: 1
Region mask:
0 0 0 0 0 0 
0 0 0 0 0 0 
0 0 1 0 0 0 
0 0 0 0 0 0 
0 0 0 0 0 0 

Secondary Region #1
Region color: 5
Region count: 1
Region mask:
0 0 0 0 0 0 
0 0 0 0 0 0 
0 0 0 1 0 0 
0 0 0 0 0 0 
0 0 0 0 0 0 

Secondary Region #2
Region color: 4
Region count: 1
Region mask:
0 0 0 0 0 0 
0 0 0 0 0 0 
0 0 0 0 0 0 
0 0 0 1 0 0 
0 0 0 0 0 0 

Selected color: 4

------------------------------------

Step #3
Game board: 
4 4 4 4 4 4 
4 4 4 4 4 4 
4 4 4 5 4 4 
4 4 4 4 4 4 
4 4 4 4 4 4 

Primary Region

Region color: 4
Region count: 29
Region mask:
1 1 1 1 1 1 
1 1 1 1 1 1 
1 1 1 0 1 1 
1 1 1 1 1 1 
1 1 1 1 1 1 

Secondary Region #0
Region color: 5
Region count: 1
Region mask:
0 0 0 0 0 0 
0 0 0 0 0 0 
0 0 0 1 0 0 
0 0 0 0 0 0 
0 0 0 0 0 0 

Selected color: 5

------------------------------------

Step #4
Game board: 
5 5 5 5 5 5 
5 5 5 5 5 5 
5 5 5 5 5 5 
5 5 5 5 5 5 
5 5 5 5 5 5 

Primary Region

Region color: 5
Region count: 30
Region mask:
1 1 1 1 1 1 
1 1 1 1 1 1 
1 1 1 1 1 1 
1 1 1 1 1 1 
1 1 1 1 1 1 

Solved in 4 step(s):
3 2 4 5 

这篇关于车削不同颜色的2D阵列成单一颜色最优的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆