版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_33054265/article/details/51474429
何为全排列,我想这个就不用多解释了吧,如果真不知道,可以自行上网查询。现在的重点是如何编程实现它,简要介绍一下我的全排列的递归算法思想:若用字符数组a[n]来存储数据,先固定a[0]到a[k](k从0到n-1),再生成a[k+1]到a[n-1]的全排列(具体采用交换元素的步骤来实现)。
C代码如下
#include<stdio.h>
#include<string.h>
void permute(char *a, int num, int i);
void permute(char *a, int num, int i){
int j;
char temp;
if(i >= num){
puts(a);
}else{
for(j = i; j < num; j++){
temp = a[i];//交换a[i]和a[j]
a[i] = a[j];
a[j] = temp;
permute(a, num, i+1);
temp = a[i];//回溯
a[i] = a[j];
a[j] = temp;
}
}
}
int main(void){
char a[] = "ABC";
permute(a, strlen(a), 0);
return 0;
}
现在我们可以借助上述全排列的算法思想,实现输出任意阶幻方的所有情形。比如三阶幻方,可用1-9依次填满所有幻方格子,然后使用全排列,每次排列记得检查只有符合幻方要求的情形才输出来。
c++代码如下:
#include <iostream>
#include <vector>
using namespace std;
void createMagicSquare(vector< vector<int> > &matrix, int n, int i, int sum);
int isEqualToSum(vector< vector<int> > matrix, int n, int sum);
void showMagicSquare(vector< vector<int> > matrix, int n);
void showMagicSquare(vector< vector<int> > matrix, int n){
static int count;
printf("第%d种情形:\n", ++count);
for(int i = 0; i < n; i++){
for(int j = 0; j < n; j++)
printf("%2d", matrix[i][j]);
cout << endl;
}
}
int isEqualToSum(vector< vector<int> > matrix, int n, int sum){
int rowSum, i, j;
vector<int> colSum(n);
int diagonalSum[2] = {0};//两条对角线的和
for(i = 0; i < n; i++){
for(j = rowSum = 0; j < n; j++){
rowSum += matrix[i][j];
if(rowSum > sum)//当每行当前元素之和大于sum时已经不满足幻方要求
return 0;
colSum[j] += matrix[i][j];
if(colSum[j] > sum)//当每列当前元素之和大于sum时已经不满足幻方要求
return 0;
if(i == j)
diagonalSum[0] += matrix[i][j];
if(i+j == n-1)
diagonalSum[1] += matrix[i][j];
//当每条对角线当前元素之和大于sum时已经不满足幻方要求
if(diagonalSum[0] > sum || diagonalSum[1] > sum)
return 0;
}
if(rowSum != sum)
return 0;
}
for(j = 0; j < n && colSum[j] == sum; j++)
;
if(j != n)
return 0;
if(diagonalSum[0] != sum || diagonalSum[1] != sum)
return 0;
return 1;
}
void createMagicSquare(vector< vector<int> > &matrix, int n, int i, int sum){
int temp, j;
int num = n * n;
if(i >= num && isEqualToSum(matrix, n, sum)){
showMagicSquare(matrix, n);
}else{
for(j = i; j < num; j++){//二维矩阵用一个下标表示
temp = matrix[i/n][i%n];
matrix[i/n][i%n] = matrix[j/n][j%n];
matrix[j/n][j%n] = temp;
createMagicSquare(matrix, n, i+1, sum);
temp = matrix[i/n][i%n];
matrix[i/n][i%n] = matrix[j/n][j%n];
matrix[j/n][j%n] = temp;
}
}
}
int main(){
int n, sum, i, j;
cout << "请输入幻方阶数:";
cin >> n;
sum = n*(n*n + 1)/2;//n阶幻方要求的每行每列每条对角线的和
vector< vector<int> > matrix(n);
for(i = 0; i < n; i++)
matrix[i].resize(n);
//将1到n*n填入幻方格子
for(i = 0; i < n; i++)
for(j = 0; j < n; j++)
matrix[i][j] = i*n + j + 1;
createMagicSquare(matrix, n, 0, sum);
return 0;
}
不过这种实现幻方的算法时间复杂度太大(O(N!),N为数据规模即幻方的格子数),如过追求效率,该算法实在是不可取。有一种连续摆放法,幻方要根据阶数分三种情况:奇数,能被4整除的偶数和不能被4整除的偶数;不同的情形数字摆放的方法不同,其时间复杂度为O(N),有兴趣的读者可以自行上网查阅,此处我就不再细说该方法。但是这种连续摆放法只能输出幻方的一种情形,如过要输出所有情形,就得进行翻转对折等步骤,而当阶数为4时,就已经很难想尽所有变换方法,故当输出所有情形时,连续摆放法也很难实现。
文章若有不足处,还请大家指正!谢谢!