如何解决另一个版本的Kakuro

How to solve another version of Kakuro

本文关键字:另一个 版本 Kakuro 解决 何解决      更新时间:2023-10-16

问题是,在(h+1)*(w+1)的表中,第一行包含w个值:a[1]。。。a[w]填充第二个。。。第(w+1)列。第一列包含h个值:b[1]。。。b[h]填充第二个。。。第(h+1)行。sum(a[i])等于sum(b[i])。

问题是给出一个可能的解决方案:result,使得某个K的sum(result[i][K])等于a[i],result[i][K]!=结果[j][K](i!=j并且0<i<h+1)。行也是同样的规则。PS:所有的整数都是正的。

例如:

a[] = {10, 3, 3}, b[] = {9, 7}
 //   10  3  3
 // 9  6  2  1
 // 7  4  1  2
result = {6, 2, 1;
          4, 1, 2}

它就像卡库罗,但不一样。我不知道该应用哪种算法,如果有人知道如何解决,请给我一些帮助。非常感谢。

您总是可以通过回溯来解决问题。这里的基本思想是:从上到下,从左到右,在部分填充的表中尝试一个有效的值,当这个值没有得到解决方案时回溯。

带注释solve:的C++中的最小示例

#include <algorithm>
#include <iostream>
#include <iterator>
#include <memory>
class Problem {
public:
    template<class AIter, class BIter>
    Problem(AIter abegin, AIter aend, BIter bbegin, BIter bend)
    :   m_width(std::distance(abegin, aend))
    ,   m_height(std::distance(bbegin, bend))
    ,   m_table(new int[(m_width + 1) * (m_height + 1)])
    {
        std::fill(m_table.get(), m_table.get() + (m_width + 1) * (m_height + 1), 0);
        for(size_t i = 0; i < m_width; ++i)
            m_table[i + 1] = *abegin++;
        for(size_t j = 0; j < m_height; ++j)
            m_table[(j + 1) * (m_width + 1)] = *bbegin++;
    }
    bool Solve() { return solve(0, 0); }
    int operator()(size_t i, size_t j) const;
private:
    int a(size_t i) const { return m_table[i + 1]; }
    int b(size_t j) const { return m_table[(j + 1) * (m_width + 1)]; }
    int get(size_t i, size_t j) const { return m_table[(j + 1) * (m_width + 1) + i + 1]; }
    void set(size_t i, size_t j, int value) { m_table[(j + 1) * (m_width + 1) + i + 1] = value; }
    int colSum(size_t i) const;
    int rowSum(size_t j) const;
    bool solve(size_t i, size_t j);
    size_t m_width, m_height;
    std::unique_ptr<int[]> m_table; // (width + 1) x (height + 1)
};
int Problem::colSum(size_t i) const {
    int sum = 0;
    for(size_t j = 0; j < m_height; ++j)
        sum += get(i, j);
    return sum;
}
int Problem::rowSum(size_t j) const {
    int sum = 0;
    for(size_t i = 0; i < m_width; ++i)
        sum += get(i, j);
    return sum;
}
// solves column-wise using backtracking
bool Problem::solve(size_t i, size_t j) {
    size_t width = m_width, height = m_height;
    // past last column?
    if(i >= width) {
        // found solution
        return true;
    }
    // remainder in column and row
    int remColSum = a(i) - colSum(i);
    int remRowSum = b(j) - rowSum(j);
    // early break
    if(remColSum <= 0 || remRowSum <= 0)
        return false;
    // starting at the minimal required value (1 or remColSum if on last row)
    int startValue = j + 1 < height ? 1 : remColSum;
    // remaining row sum cannot support the starting value
    if(remRowSum < startValue)
        return false;
    // end value minimum remaining sum
    int endValue = remColSum < remRowSum ? remColSum : remRowSum;
    // on last element must equal starting value
    if(i + 1 == width && j + 1 == height && startValue != endValue)
        return false;
    // column-wise i.e. next cell is (i, j + 1) wrapped
    int nextI = i + (j + 1) / height;
    int nextJ = (j + 1) % height;
    for(int value = startValue; value <= endValue; ++value) {
        bool valid = true;
        // check row up to i
        for(size_t u = 0; u < i && valid; ++u)
            valid = (get(u, j) != value);
        // check column up to j
        for(size_t v = 0; v < j && valid; ++v)
            valid = (get(i, v) != value);
        if(!valid) {
            // value is invalid in partially filled table
            continue;
        }
        // value produces a valid, partially filled table, now try recursing
        set(i, j, value);
        // upon first solution break
        if(solve(nextI, nextJ))
            return true;
    }
    // upon failure backtrack
    set(i, j, 0);
    return false;
}
int Problem::operator()(size_t i, size_t j) const {
    return get(i, j);
}
int main() {
    int a[] = { 10, 3, 3 };
    int b[] = { 9, 7 };
    size_t width = sizeof(a) / sizeof(*a);
    size_t height = sizeof(b) / sizeof(*b);
    Problem problem(a, a + width, b, b + height);
    if(!problem.Solve()) {
        std::cout << "No solution" << std::endl;
    }
    for(size_t j = 0; j < height; ++j) {
        if(j == 0) {
            std::cout << " ";
            for(size_t i = 0; i < width; ++i)
                std::cout << "  " << a[i];
            std::cout << std::endl;
        }
        std::cout << b[j];
        for(size_t i = 0; i < width; ++i) {
            int value = problem(i, j);
            if(value == 0)
                std::cout << "   ";
            else
                std::cout << "  " << value;
        }
        std::cout << std::endl;
    }
    return 0;
}