一个古老的数学问题(魔方阵问题)(散分,UP有分,来者有分)。

syl08341 2003-05-11 09:28:31
这个贴子是散分贴,来者有分。
接分的同志请注意:请每天只UP一次,如果UP多次,只给UP一次的分。

这个贴子以前贴了一次,没有等到结果,现在重新贴一次。希望能够有高手解答
如果能够解答出来的话,另外开给分贴子给分。
http://expert.csdn.net/Expert/topic/1732/1732898.xml?temp=.6524622
什么是魔方阵?
魔方阵是由1至n*n(3 <= N <= 9)个数组成方阵的。要求横加、竖加、斜加都相等。
如1 2 3
4 5 6
7 8 9组成的魔方阵为:

6 1 8
7 5 3
2 9 4
横加、竖加、斜加都相等于15

当然,对于奇数阶的魔方阵可以有简便的方法。
(方阵转45度,之后数往里压,然后再交换)。

我现在并不想用这种取巧的办法。而是希望算出所有的可能排列之后,把符合魔方阵的排列显示出来,并统计一共有多少种排列方法。我以前编写过魔方阵问题的程序。利用递归。这种方法只能用于3阶,即上图。4阶魔方阵,机器就无法算出结果了。

问题1:
有一个思路,可是无法编写出来代码。(100分)
每次两个数字交换位置,通过交换位置来排列出魔方阵的所有可能。
比如第一次是头两个数字交换位置,
第二次是第三个和第一个交换位置,
第三次是第三个和第二个交换位置…
谁能够用把这个思路的代码写出来?

请教高手
问题2:如果有更好的算法,能够得到所有的可能的排列,然后从中找出符合魔方阵的方阵来。)100分)。
问题3:如果再有这个算法的代码,加分100。
这个贴子是散分贴,来者有分。
如果能够解决上述三个问题中的一个或多个,我另外开一个给分的贴子送分。
问题4:我下面的三个程序中,有一个用递归的程序中,存在BUG,解决这个BUG的,加分50。以前用递归做出来过。很长时间没用递归了,手都生了。如果自己编写用递归做出来的话,加分50


以下是从以前的贴子中COPY出来的一些内容,也许会对您解答这个问题有所帮助。
小时候,玩魔方阵的时候,找到一个方法。
就是对于所有的魔方阵,都可以用把它的内圈看成一个小魔方阵的方法来解决。
比如说五阶魔方阵,内圈可以看成一个三阶魔方阵,先排好内圈,再排外圈。
七阶魔方阵,可以把内圈看成一个五阶魔方阵。把五阶排好后,再排外圈。
六阶魔方阵,内圈可以看成一个四阶魔方阵。
用这个方法。小时候用手工排列,排出过七阶魔方阵。再高阶的,就排不出来了。

有没有算法方面的高手,提供一个思路。可以解决魔方阵的问题。
JennyVenus(项链啊,首饰啊,金银珠宝啊,月光宝盒。) 的程序对于奇数阶的魔方阵都好用。问题是这个算法如何证明它正确。

再有,我所说的,如何能够等到所有的排列?(通过数字交换位置,因为我认为数字交换位置应该是找到全排列的比较好的方法。否则的话,程序的计算量将大到现有的台式机无法承受的地步。)


To: maohbao() :上面JennyVenus(项链啊,首饰啊,金银珠宝啊,月光宝盒。) 的程序就是你所说的算法。编写的非常不错,代码简洁,明了。运行速度也很快。问题是,你如何证明它是对的,再有,如何能够得到所有的排列中,有多少种排列方法。对于三阶,有8种,全是一样的,对于五阶,我以前手排,就排出过两种不同的。问题是一共有多少种不同的。


下面给出三个程序
一个是回复人: JennyVenus() ( ) 信誉:151给出的一个比较经典的程序代码。
一个是我新编写的通过递归调用得到魔方阵的方法。有BUG,可以得出部分正确的解。
一个是我编写的最笨的魔方阵算法。


奇数
#include<stdio.h>
#include<conio.h>
#define MAX 2
void main()
{
int arr[MAX+1][MAX+1],val=1,i,j,k;
clrscr();
for(i=0;i<=MAX;i++)
for(j=0;j<=MAX;j++)
arr[i][j]=0;
for(i=0,j=MAX/2,k=0;k<((MAX+1)*(MAX+1));k++)
{
arr[i--][j--]=val++;
if(i<0)
i=MAX;
if(j<0)
j=MAX;
if(arr[i][j]!=0)
{
i=i+2;
j=j+1;
if(i>MAX)
i%=(MAX+1);
if(j>MAX)
j%=(MAX+1);
}
}
for(i=0;i<=MAX;i++)
{
for(j=0;j<=MAX;j++)
printf("%d\t",arr[i][j]);
printf("\n");
}
getch();
}

偶数的幻方分为4的倍数和不是4的倍数的两种,4的倍数的可以看《射雕英雄传》,背了歌诀就行了,非4的倍数的不会(原理都忘了),需要扩充。




















#include <stdio.h>
#define NUM 3

int a[9], result, count;

void print()
{
for(int i = 0; i < 3; i++)
{
for(int j = 0; j < 3; j++)
{
printf("%3d", a[i*3+j]);
}
printf("\n");
}
getchar();
}

bool IsMagic() // 判断是否为魔方阵
{
int sumx, sumy, sumi[NUM], sumj[NUM];
sumx = sumy = 0;
for(int i = 0; i < NUM; i++)
sumi[i] = sumj[i] = 0;
for(i = 0; i < NUM; i++)
{
for(int j = 0; j < NUM; j++)
{
if(i == j)
sumx += a[i*NUM+j];
if(i == NUM-j-1)
sumy += a[i*NUM+j];
sumi[i] += a[i*NUM+j];
sumj[j] += a[i*NUM+j];
}
}
if(sumx != sumy) return false;
for(i = 0; i < NUM; i++)
{
if(sumi[i] != sumj[i] || sumi[i] != sumx)
return false;
}
return true;
}

void main()
{
for(int i1 = 1; i1 < 10; i1++)
{
a[0] = i1;
for(int i2 = 1; i2 < 10; i2++)
{
if(i2 == i1) continue;
a[1] = i2;
for(int i3 = 1; i3 < 10; i3++)
{
if(i3 == i1 || i3 == i2) continue;
a[2] = i3;
for(int i4 = 1; i4 < 10; i4++)
{
if(i4 == i1 || i4 == i2 || i4 == i3) continue;
a[3] = i4;
for(int i5 = 1; i5 < 10; i5++)
{
if(i5 == i1 || i5 == i2 || i5 == i3 || i5 == i4) continue;
a[4] = i5;
for(int i6 = 1; i6 < 10; i6++)
{
if(i6 == i1 || i6 == i2 || i6 == i3 || i6 == i4 || i6 == i5) continue;
a[5] = i6;
for(int i7 = 1; i7 < 10; i7++)
{
if(i7 == i1 || i7 == i2 || i7 == i3 || i7 == i4 || i7 == i5 || i7 == i6) continue;
a[6] = i7;
for(int i8 = 1; i8 < 10; i8++)
{
if(i8 == i1 || i8 == i2 || i8 == i3 || i8 == i4 || i8 == i5 || i8 == i6 || i8 == i7) continue;
a[7] = i8;
for(int i9 = 1; i9 < 10; i9++)
{
if(i9 == i1 || i9 == i2 || i9 == i3 || i9 == i4 || i9 == i5 || i9 == i6 || i9 == i7 || i9 == i8) continue;
a[8] = i9;
{
count++;
if(IsMagic())
{
result++;
print();
}
}
}
}
}
}
}
}
}
}
}
}













#include <stdio.h>
#define NUM 3

int a[NUM*NUM] = {9, 3, 8, 4, 5, 1, 7, 2, 6};
bool b[NUM*NUM+1];
int last[NUM*NUM], count, result;
int error;

bool IsMagic() // 判断是否为魔方阵
{
int sumx, sumy, sumi[NUM], sumj[NUM];
sumx = sumy = 0;
for(int i = 0; i < NUM; i++)
sumi[i] = sumj[i] = 0;
for(i = 0; i < NUM; i++)
{
for(int j = 0; j < NUM; j++)
{
if(i == j)
sumx += a[i*NUM+j];
if(i == NUM-j-1)
sumy += a[i*NUM+j];
sumi[i] += a[i*NUM+j];
sumj[j] += a[i*NUM+j];
}
}
if(sumx != sumy) return false;
for(i = 0; i < NUM; i++)
{
if(sumi[i] != sumj[i] || sumi[i] != sumx)
return false;
}
return true;
}

int GetNumber(int n, int s)
{
int end = 0;
for(int i = n+s+1; ; i++)
{
end++;
if(i == last[n]) continue;
if(end > NUM*NUM)
{
return last[n];
}
if(i > NUM*NUM)
i -= NUM*NUM;
if(b[i])
{
b[i] = false;
last[n] = i;
return i;
}
}
}

void lined(int n)
{
if(n == NUM*NUM) return;
for(int i = n; i < NUM*NUM; i++)
{
a[n] = GetNumber(n, i-n);
if(n == NUM*NUM-1)
{
count++;
if(IsMagic())
{
for(int k = 0; k < NUM; k++)
{
for(int j = 0; j < NUM; j++)
{
printf("%3d", a[k*NUM+j]);
}
printf("\n");
}
getchar();
result++;
}
}
lined(n+1);
b[last[n]] = true;
}
}

void main()
{
for(int i = 0; i <= NUM*NUM; i++)
b[i] = true;

lined(0);
}
...全文
173 40 打赏 收藏 转发到动态 举报
写回复
用AI写文章
40 条回复
切换为时间正序
请发表友善的回复…
发表回复
Panr 2003-05-13
  • 打赏
  • 举报
回复
我想来想去还是要用遍历,想办法优化吧
我估计可以在十秒内算出4x4的方阵

[妈的!CSDN又生病了,昨晚恁是发表不了流言,真是弱]
meshspring 2003-05-12
  • 打赏
  • 举报
回复
up
syl08341 2003-05-12
  • 打赏
  • 举报
回复
感谢大家捧场。
回复的人太多了。先把贴子结了。
如果有人想回答这个问题的话。
请给我发短信。
解决问题之后给分。
wuhuanjob 2003-05-12
  • 打赏
  • 举报
回复
我都不懂的!只看出来点程序的写法规格!呵呵!我是菜鸟!
goodboyyxh 2003-05-12
  • 打赏
  • 举报
回复
up
lshadow 2003-05-12
  • 打赏
  • 举报
回复
好多啊,没有看完,帮你up
xingyaorz 2003-05-12
  • 打赏
  • 举报
回复
up
cyxcry 2003-05-12
  • 打赏
  • 举报
回复
up
rabithao 2003-05-12
  • 打赏
  • 举报
回复
帮你up
Panr 2003-05-12
  • 打赏
  • 举报
回复
有意思,mark 先
blue2moon 2003-05-12
  • 打赏
  • 举报
回复
佩服!得向你好好学习了!
syl08341 2003-05-12
  • 打赏
  • 举报
回复
今晚结贴
dizzo 2003-05-12
  • 打赏
  • 举报
回复
路过,up一下
syl08341 2003-05-12
  • 打赏
  • 举报
回复
/*
下面的程序是我消耗了N(n <= 9!)个脑细胞后新想出来的一个方法。
贴出来,供大家参考。(只能用于三阶魔方阵。)
只需要进行两重循环,即可得到所有可能的三阶魔方阵。
1 2 3
4 5 6
7 8 9
思路是:通过三阶魔方阵的特性。5必然居中。所有只要知道
位置1, 2的两个数字,其它的数字可以通过计算求出来。
用这个算法,只需要进行四十次计算,即可得到所有的三阶魔方阵。
一共为8个
*/
#include <stdio.h>

int a[9], count, result;

bool InA(int num)
{
if(num < 0 || num > 9) return true;
for(int i = 0; i < 9; i++)
if(num == a[i]) return true;
return false;
}

bool make_magic()
{
int temp;
count++;
a[4] = 5;
temp = 15-a[0]-a[1];
if(InA(temp)) return false;
else a[2] = temp;
temp = 10 - a[0];
if(InA(temp)) return false;
else a[8] = temp;
temp = 10 - a[2];
if(InA(temp)) return false;
else a[6] = temp;
temp = 10 - a[1];
if(InA(temp)) return false;
else a[7] = temp;
temp = 15-a[0]-a[6];
if(InA(temp)) return false;
else a[3] = temp;
temp = 10 - a[3];
if(InA(temp)) return false;
else a[5] = temp;

return true;
}

void print()
{
result++;
for(int i = 0; i < 3; i++)
{
for(int j = 0; j < 3; j++)
{
printf("%3d", a[i*3+j]);
}
printf("\n");
}
getchar();
}

void init()
{
for(int i = 2; i < 9; i++)
a[i] = 0;
}

void main()
{
for(int i = 1; i < 10; i++)
{
if(i == 5) continue;
a[0] = i;
for(int j = 1; j < 10; j++)
{
if(j == i || j == 5 || i+j < 6 || i+j > 14) continue;
a[1] = j;
if(make_magic())
print();
init();
}
}
}
ulovexd 2003-05-11
  • 打赏
  • 举报
回复
老乡~!我帮你UP
嘻嘻!
天限天空 2003-05-11
  • 打赏
  • 举报
回复
我研究了3天才车了个6面出来

并且 只有 15%的概率

写算法,不知要研究多久



关注
王集鹄 2003-05-11
  • 打赏
  • 举报
回复
如果用穷尽法来算到一定的程度就算不下去了~~
9!=362880
16!=20922789888000
27!=10888869450418352160768000000
…………

如下是一个立体的幻方~~
每个平面的和都一样~~
全当up~~

..18┌───23┬───┐01
.20┌┼──07┬┼──┐15
04┌┼┼─12┬┼┼─┐26|
.|22├┈┈┼03┼┈┼┼┤17
.09├┼┈┈14┼┼┈┼┤19
11├┼┼─25┼┼┼─┤06|
.|02└┈┈┼16┴┈┼┼┘24
.13└┈┈┈21┴┈┈┼┘08
27└───05┴───┘10
FreeSeagull 2003-05-11
  • 打赏
  • 举报
回复
up
syl08341 2003-05-11
  • 打赏
  • 举报
回复
up
sagasonme 2003-05-11
  • 打赏
  • 举报
回复
Up!!!
加载更多回复(20)

16,472

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Web++
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧