首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >3×3幻方递归

3×3幻方递归
EN

Stack Overflow用户
提问于 2015-06-22 13:42:17
回答 3查看 2.2K关注 0票数 0

我正在努力寻找3X3魔方的所有可能的解决方案。应该有8种解决方案。

我的代码得到了它们,但是有很多重复。我很难跟踪递归步骤,以了解为什么要获得所有的重复。

代码语言:javascript
复制
// This program finds all solutions to the magic square for a 3X3     
// square where each column, row and diagonal sum is equal

#include <iostream>
using namespace std;
#define SQUARE_SIZE 9

int anyLine = 0;
int currLine = 0;
int numSolutions = 0;


// swap two values in the square.
void swap(int arr[], int idxa, int idxb)
{
    int tmp = arr[idxa];
    arr[idxa] = arr[idxb];
    arr[idxb] = tmp;
}

void printArray(int arr[])
{
    for (int i = 0; i < SQUARE_SIZE; i++)
    {
        cout << arr[i] << " ";
        if ((i + 1) % 3 == 0)
            cout << endl;
    }
    cout << endl;
}

// this function tests to see if we have a "good" arrangement of numbers            
// i.e the sum of each row, column and diagonal is equal

bool checkArr(int arr[])
{
    anyLine = arr[0] + arr[1] + arr[2];
    currLine = 0;
    for (int i = 0; i < SQUARE_SIZE; i++)
    {
        currLine += arr[i];
        if ((i + 1) % 3 == 0)
        {
            if (currLine != anyLine)
                return false;
            currLine = 0;
        }
    }

    // check vertically
    for (int col = 0; col <3; col++)
    {
        for (int row = 0; row <3; row++)
        {
            currLine += arr[col + 3 * row];
        }

        if (currLine != anyLine)
            return false;

        currLine = 0;
    }

    // check the diagonals
    if ((arr[2] + arr[4] + arr[6]) != anyLine)
        return false;

    if ((arr[0] + arr[4] + arr[8]) != anyLine)
        return false;

    return true;
}

void solve(int arr[], int pos)
{
    if (pos == 8)
    {
        if (checkArr(arr))
        {
            printArray(arr);
            numSolutions++;
        }
    } else 
    {
        for (int i = 0; i < 9; i++)
        {
            if (i == pos) continue;

            if (checkArr(arr))
            {
                printArray(arr);
                numSolutions++;
            }
            swap(arr, pos, i);
            solve(arr, pos + 1);
        }
    }
}

int main()
{
    int arr[SQUARE_SIZE] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };

    solve(arr, 0);
    cout << "number of solutions is: " << numSolutions << endl;

    return 0;
}
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2015-06-22 14:02:15

基本上,您正在使用递归置换算法查找数组的所有排列。

有四件事你需要改变:

首先,从pos开始循环,而不是0。

第二,在递归之后返回交换元素(回溯)

第三,只有在生成了每个完整的排列(当pos = 8)之后才进行测试,否则您将不止一次地测试相同的排列。

第四,用自己交换元素(即不交换元素)是一个有效的排列,因为元素可以保留在它们原来的位置上。

代码语言:javascript
复制
void solve(int arr[], int pos)
{
    if (pos == 8)
    {
        if (checkArr(arr))
        {
            printArray(arr);
            numSolutions++;
        }
    }
    else
    {
        for (int i = pos ; i < 9; i++)
        { 
            swap(arr,pos,i);
            solve(arr,pos +1);
            swap(arr,pos,i); 
        }
    }
}

演示

票数 1
EN

Stack Overflow用户

发布于 2015-06-22 14:04:59

您的代码从两个位置调用printArray --递归的基本情况(即pos == 8时)和调用swap之前的循环中。第二个调用是不必要的:当您到达pos == 8状态时,您将得到相同的平方。

这就减少了重复的数量,但是由于你生成正方形的方式,它并不能消除它们。你需要跟踪已经印好的东西。一种方法是创建一组您已经找到的解决方案,并在打印新发现的解决方案之前对其进行检查:

代码语言:javascript
复制
set<int> seen;

int key(int arr[]) {
    return arr[0]
    + 10 * arr[1]
    + 100 * arr[2]
    + 1000 * arr[3]
    + 10000 * arr[4]
    + 100000 * arr[5]
    + 1000000 * arr[6]
    + 10000000 * arr[7]
    + 100000000 * arr[8];
}

 void printArray(int arr[]) {
    if (!seen.insert(key(arr)).second) {
        // second is set to false when a duplicate is found
        return;
    }
    numSolutions++;
    for (int i = 0; i < SQUARE_SIZE; i++) {
        cout << arr[i] << " ";
        if((i+1) % 3 == 0)
            cout << endl;
    }
    cout << endl;
 }

演示。

关于上面的解决方案,有几点需要注意:

  • key(int[])将平方转换为单个十进制数,因此这种方法只适用于由十进制数字组成的平方。对于任意数字,您需要一种不同的策略,例如,使用一组逗号分隔的字符串。
  • 解决方案的计数被移到printArray(int[])。您可以完全放弃numSolutions,转而使用seen.size();它提供了相同的答案。
票数 1
EN

Stack Overflow用户

发布于 2015-06-22 14:35:43

如果您不想为了锻炼的目的递归地解决这个问题,我建议您使用std::next_permutation

代码语言:javascript
复制
void solve(int(&arr)[SQUARE_SIZE], int pos)
{
    sort(std::begin(arr), std::end(arr));
    do {
        if (checkArr(arr))  { 
            numSolutions++;
            printArray(arr);
        }
    } while (next_permutation(begin(arr), end(arr)));   
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/30981523

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档