【问题标题】:Recursive algorithm to find all possible solutions in a nonogram row递归算法在非图行中找到所有可能的解决方案
【发布时间】:2017-11-08 01:25:00
【问题描述】:

我正在尝试以一种蛮力的方式编写一个简单的非图求解器,但我被困在一个相对简单的任务上。假设我有一排长度为 10 的线索 [2,3]

所以解决方案是:

$$-$$$----
$$--$$$---
$$---$$$--
$$----$$$-
$$-----$$$
-$$----$$$
--$$---$$$
---$$--$$$
----$$-$$$
-$$---$$$-
--$$-$$$--

我想为一行找到所有可能的解决方案 我知道我必须单独考虑每个块,并且每个块将有一个可用空间 n-(剩余块长度之和 + 剩余块数)但我不知道如何从这里开始

【问题讨论】:

  • 哪种语言?
  • @alseether,这是一个算法问题,所以语言不相关。 OP 对这个过程很感兴趣。
  • @JonathanM 是的,我知道,但我会尝试用 C++ 来做,只是想知道他们是否可以。
  • 顺便说一句,我认为您缺少一些组合,-$$-$$$--- 不是也有效吗?
  • @alseether 是的,我可能确实错过了一些组合。语言与我无关。

标签: algorithm recursion


【解决方案1】:

嗯,这个问题已经有了很好的答案,所以把这个当成是python实力的广告吧。

def place(blocks,total):
    if not blocks: return ["-"*total]
    if blocks[0]>total: return []

    starts = total-blocks[0] #starts = 2 means possible starting indexes are [0,1,2]
    if len(blocks)==1: #this is special case
        return [("-"*i+"$"*blocks[0]+"-"*(starts-i)) for i in range(starts+1)]

    ans = []
    for i in range(total-blocks[0]): #append current solutions
        for sol in place(blocks[1:],starts-i-1): #with all possible other solutiona
            ans.append("-"*i+"$"*blocks[0]+"-"+sol)

    return ans

测试它:

for i in place([2,3,2],12):
    print(i)

产生如下输出:

$$-$$$-$$---
$$-$$$--$$--
$$-$$$---$$-
$$-$$$----$$
$$--$$$-$$--
$$--$$$--$$-
$$--$$$---$$
$$---$$$-$$-
$$---$$$--$$
$$----$$$-$$
-$$-$$$-$$--
-$$-$$$--$$-
-$$-$$$---$$
-$$--$$$-$$-
-$$--$$$--$$
-$$---$$$-$$
--$$-$$$-$$-
--$$-$$$--$$
--$$--$$$-$$
---$$-$$$-$$

【讨论】:

  • 太棒了!感谢python解决方案!
  • 非常好的紧凑的解决方案
【解决方案2】:

这是我得到的:

#include <iostream>
#include <vector>
#include <string>

using namespace std;

typedef std::vector<bool> tRow;

void printRow(tRow row){
    for (bool i : row){
        std::cout << ((i) ? '$' : '-');
    }
    std::cout << std::endl;
}

int requiredCells(const std::vector<int> nums){
    int sum = 0;
    for (int i : nums){
        sum += (i + 1); // The number + the at-least-one-cell gap at is right
    }
    return (sum == 0) ? 0 : sum - 1; // The right-most number don't need any gap
}

bool appendRow(tRow init, const std::vector<int> pendingNums, unsigned int rowSize, std::vector<tRow> &comb){
    if (pendingNums.size() <= 0){
        comb.push_back(init);
        return false;
    }
    int cellsRequired = requiredCells(pendingNums);
    if (cellsRequired > rowSize){
        return false;   // There are no combinations
    }
    tRow prefix;
    int gapSize = 0;
    std::vector<int> pNumsAux = pendingNums;
    pNumsAux.erase(pNumsAux.begin());
    unsigned int space = rowSize;
    while ((gapSize + cellsRequired) <= rowSize){
        space = rowSize;
        space -= gapSize;
        prefix.clear();
        prefix = init;
        for (int i = 0; i < gapSize; ++i){
            prefix.push_back(false);
        }
        for (int i = 0; i < pendingNums[0]; ++i){
            prefix.push_back(true);
            space--;
        }
        if (space > 0){
            prefix.push_back(false);
            space--;
        }
        appendRow(prefix, pNumsAux, space, comb);
        ++gapSize;
    }
    return true;
}

std::vector<tRow> getCombinations(const std::vector<int> row, unsigned int rowSize) {
    std::vector<tRow> comb;
    tRow init;
    appendRow(init, row, rowSize, comb);
    return comb;
}

int main(){
    std::vector<int> row = { 2, 3 };

    auto ret = getCombinations(row, 10);

    for (tRow r : ret){
        while (r.size() < 10)
            r.push_back(false);

        printRow(r);
    }

    return 0;

}

我的输出是:

$$-$$$----

$$--$$$---

$$---$$$--

$$----$$$--

$$-----$$$

-$$-$$$----

-$$--$$$--

-$$---$$$-

-$$----$$$-

--$$-$$$--

--$$--$$$-

--$$---$$$

---$$-$$$-

---$$--$$$

----$$-$$$

当然,这一定是绝对可以改进的。

注意:我没有比已经写的案例更多地测试它

希望对你有用

【讨论】:

  • 如果忘记了任何情况,请告诉我,我将编辑此答案
  • 不,我实际上错了,“填充循环”必须达到 10,而不是像我那样达到 9
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-03
  • 1970-01-01
  • 2013-07-22
  • 1970-01-01
  • 2023-04-03
相关资源
最近更新 更多