3×3幻方递归
3 X 3 magic square recursively
我正在努力寻找3X3幻方的所有可能的解决方案。应该正好有8个解决方案。
我的代码得到了它们,但有很多重复。我很难追踪递归步骤,看看为什么我得到了所有的重复。
// 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;
}
基本上,您使用递归排列算法来查找数组的所有排列。
有4件事你需要改变:
首先,从pos开始循环,而不是0
第二,在递归(回溯)之后交换元素
第三,只在生成每个完整排列后进行测试(当pos=8时),否则将多次测试相同的排列。
第四,将元素与其本身交换(即不交换)是一种有效的置换,因为元素被允许保持在其原始位置。
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);
}
}
}
演示
您的代码从两个位置调用printArray
——递归的基本情况(即当pos == 8
时)和调用swap
之前的循环中。第二个调用是不必要的:当你到达pos == 8
状态时,你会得到相同的平方。
这减少了重复的数量,但并不能消除它们,因为你生成正方形的方式。你需要跟踪打印的内容。一种方法是制作一组你找到的解决方案,并在打印新找到的解决方法之前进行检查:
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()
;它提供了相同的答案
如果你不想为了练习而递归地解决这个问题,我建议使用std::next_permutation
:
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)));
}
相关文章:
- 通过递归进行因子分解
- 递归函数计算序列中的平方和(并输出过程)
- 使用递归的数组的最小值.这是怎么回事
- 递归列出所有目录中的C++与Python与Ruby的性能
- 递归计数给定目录的文件和所有目录
- 如何在BST的这个简单递归实现中消除警告
- C++:正在检查LinkedList中的回文-递归方法-错误
- 递归模板化函数不能分配给具有常量限定类型"const tt &"的变量"state"
- 递归无序映射
- TSP递归解的迭代形式
- 如何在Elixir中调用递归函数并行
- 返回递归调用和仅递归调用的区别
- 数组元素打印的递归方法
- 使用递归时获取变量的奇怪值
- 如何在C++中递归地按相反顺序打印集合
- 手工编写的递归上升语法分析器中的递归左递归
- 非递归(非递归)汽车制造
- 3×3幻方递归
- 没有基本大小写的递归和递归函数之后的语句
- 递归,递归,再递归一次