递归解决全排列和幻方

来源:互联网 发布:文件还原软件 编辑:程序博客网 时间:2024/06/06 02:57

何为全排列,我想这个就不用多解释了吧,如果真不知道,可以自行上网查询。现在的重点是如何编程实现它,简要介绍一下我的全排列的递归算法思想:若用字符数组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时,就已经很难想尽所有变换方法,故当输出所有情形时,连续摆放法也很难实现。

文章若有不足处,还请大家指正!谢谢!

0 0
原创粉丝点击