智力游戏--九连环的算法之一

havelife 2002-11-02 12:22:58
关键词:九连环、N连环、递归、拆解、安装


一、九连环简介

九连环游戏是中国人自己发明的,它的历史非常悠久,据说是起源于战国时期。

九连环主要是由一个框架和九个圆环组成:每个圆环上连有一个直杆,而这个直杆则在后面一个圆环内穿过,九个直杆的另一端用一块木板或圆环相对固定。

二、九连环的规律

通过玩九连环你就会发现存在这样一个规律:

(1)第 1 环可以自由上下
(2)而上/下第 n 环时(n>1),则必须满足:
(a)第 n-1 个环在架上
(b)前 n-2 个环全部在架下

三、拆解/安装的过程

正确的拆解是先以第 9 环为目标,先拆下它,简化为拆一个 8 连环。接着再也第 8 环为目标,拆下它,简化为拆一个 7 连环。以此类推,直至全部拆解。

其实安装和拆解是一个道理,因为他们均是使用上面说的规律来完成的。
正确是安装也是先以第 9 环为目标,先装上它,简化为装一个 8 连环。接着再也第 8 环为目标,装上它,简化为装一个 7 连环。以此类推,直至全部安装。
当然,现在这么说是便于理解,当你深刻的理解了上面所说的规律后,就会发现,安装上第 9 环后,问题可以被简化为装一个 7 连环,而当装上第 7 环后,问题就被简化为装一个 5 连环了,呵呵,就是这样的,不知道你现在是否明白我的意思……

四、一个猜想

仔细观察九连环的结构、思考九连环的规律及拆解/安装的过程,你是不是有一种感觉:九连环跟递归一定有联系。你看,递归的基本思想是把一个大的问题分解为一个规模较小的问题,从这些较小问题的解,构造出大问题的解,而这些规模较小的问题,用同样的方法分解成更小的问题,从更小问题的解,构造出较小的问题,一层层下去,一般最后总是可以分解到可以直接求解的小问题。嘿嘿,九连环的拆解/安装多么的符合这个规律啊……^_^

五、算法实现

以下是算法实现,程序写的很简洁,省略了很多功能的实现,比如计数等,如果你觉得有必要的话,可以自行添加上去,我相信很容易,并不要很多的改动。

The C Code:

/*任意 N 连环均适用 */
/*程序设计:吴文绛 */
/*腾讯:3908000 */
/*日期:2002/08/19 */

void DownRing(int n)
{
if(n>2) DownRing(n-2);
printf("下第%d环\n",n);
if(n>2) UpRing(n-2);
if(n>1) DownRing(n-1);
}

void UpRing(int n)
{
if(n>1) UpRing(n-1);
if(n>2) DownRing(n-2);
printf("上第%d环\n",n);
if(n>2) UpRing(n-2);
}

void main()
{
printf("拆解\n");
DownRing(9);
printf("安装\n");
UpRing(9);
printf("结束\n");
}

...全文
282 14 打赏 收藏 转发到动态 举报
写回复
用AI写文章
14 条回复
切换为时间正序
请发表友善的回复…
发表回复
crazy_lazy_pig 2002-11-12
  • 打赏
  • 举报
回复
是啊,10点之前做行政工作,10点之后写程序

苦啊
havelife 2002-11-08
  • 打赏
  • 举报
回复
倒,看你发帖子的时间,都是在晚上,上班很忙8,crazy_lazy_pig。。。
havelife 2002-11-08
  • 打赏
  • 举报
回复
f(n)=f(n-2)+1+f(n-2)+f(n-1)
第一个f(n-2)为拿去前n-2环的总步数
之所以加1是指拿掉第n环
第二个f(n-2)为装上前n-2环的总步数
最后的f(n-1)是在前两步的基础上,n连环简化为n-1连环,解开n-1连环的总步数,从而就找到了n连环和n-1连环的关系。
化简,得
f(n)=f(n-1)+2f(n-2)+1
你得式子是正确的。

havelife 2002-11-07
  • 打赏
  • 举报
回复
胡说,偶的程序包括了 n=1,和 n=2 的情况了,程序控制的很好,
是最简洁的写法了8,偶的主程序中,
是进行了九连环的拆解和安装,如果不信偶的程序,
你可以在main()中
尝试调用
....
DownRing(1);
UpRing(1);
DownRing(2);
UpRing(2);
....

对于你所说的f(1)=f(2)=1是技术问题,我不同意你的看法,因为
这样理解九连环不符合规律,九连环的法则我在文章的开头就已经
说明白了,拿第2环的话,第1环须在环外,在这里,第1环的状态理解
为"在环上",之所以这样理解,是一种抽象,当你尝试用二进制描述
九连环的时候就会明白了,这样才符合逻辑
N连环的规律是共通的,不论是N=2或者N>2
所以,我坚决反对将f(2)=1的情况,f(2)=2

f(2m)=2f(2m-1) (m为大于0的整数)

连环的规律必须符合这个式子!
顺便说一下,偶玩九连环在5分钟以内

crazy_lazy_pig 2002-11-07
  • 打赏
  • 举报
回复
哦,老天,是我错了
这两天竟办错事,
再次向你道歉。

关于“技术问题”,我的意思是:技术性失误,是说我错了的意思,并没有开脱些什么。
最后再问一下,我的递归式没有错吧?
crazy_lazy_pig 2002-11-06
  • 打赏
  • 举报
回复
当然是第归,是二阶的,以需要拆、装环的次数表达式为例说明之:
设f(n)表示解开n连环所需次数,则:

f(n) = f(n-2) + 1 + f(n-2) + f(n-1)
= f(n-1) + 2*f(n-2) + 1
f(1)=f(2)=1

上面的式子也说明了截九连环的方法:若想解开 n 个环,首先要把前 n-2 个环解下,再解脱第 n 个环(注意现在第 n-1 个环没有下来,即只有它一个是套着的),再套上前 n-2 个环(这时 n-1 个环都是套着的),最后解脱 n-1 个环。
大家不妨按照上面的算法重新编程,检验一下是否正确。

另外,顺便说一句,楼主的程序是错误的,千万不要仿效。
crazy_lazy_pig 2002-11-06
  • 打赏
  • 举报
回复
havelife(自由的风) :你不要不服气嘛,我也只不过是想讨论一下问题而已,大家不要伤了和气嘛。
这样,我首先对于我的一些不恰当的言辞表示歉意。
其次,希望路过的朋友注意分析havelife(自由的风) 的算法,根据我的分析,算法上是正确的。
再次,我声明:我用五分钟就能解开九连环,havelife(自由的风) 给出的公式是我亲自推导过的,我的也绝对没有错误,我给出的是递归表达式而已。另外关于f(1)=f(2)=1是技术问题,我在解九连环时,前两个总是当一步来完成的(实际上应该记数两次),这道是可以算是个小错误。

最后,关于havelife(自由的风) 的程序错误关键在于没有控制好递归出口的含义,表现在程序上就是没考虑到n=2和n=1时的两种情况,并少了“else”和大括号。部分代码应该如下:
void DownRing(int n)
{
if(n==2)
{
printf("下第2环\n");
}
else
if(n==1)
printf("下第1环\n");
else
{
DownRing(n-2);
printf("下第%d环\n",n);
UpRing(n-2);
DownRing(n-1);
}
}
havelife 2002-11-06
  • 打赏
  • 举报
回复
The C Code:(修订版)

/*任意 N 连环均适用 */
/*程序设计:吴文绛 */
/*腾讯QQ:3908000 */
/*日期:2002/08/19 */
/*修改:2002/11/6 */

void DownRing(); /*由于以下两个函数互相调用对方,因此不得不在这里 */
void UpRing(); /*加上函数说明,否则,编译将会出一点小错误了 */

void DownRing(int n)
{
if(n>2) DownRing(n-2);
printf("下第%d环\n",n);
if(n>2) UpRing(n-2);
if(n>1) DownRing(n-1);
}

void UpRing(int n)
{
if(n>1) UpRing(n-1);
if(n>2) DownRing(n-2);
printf("上第%d环\n",n);
if(n>2) UpRing(n-2);
}

void main()
{
printf("拆解\n");
DownRing(9);
printf("安装\n");
UpRing(9);
printf("结束\n");
}

havelife 2002-11-06
  • 打赏
  • 举报
回复
crazy_lazy_pig(疯狂懒猪):嘿,老兄,你错了吧,你根本没有弄懂九连环,
如果设f(n)表示解开 n 连环 所需的次数,则

f(n)=[2^(n+1)-0.5*(-1)^n-1.5]/3 是这个!!!不是你那个!!
f(1)=1
f(2)=2

解开奇连环的步骤为奇数,解开偶连环的步骤为偶数,不信你可以尝试一下
以下是一个数列:1,2,5,10,21,42,85,170,341
是解开或者装上 1 至 9 连环所需的步骤。

不过你说我的程序是错误的,偶注意了一下,的确有点小错误,就是在程序
的开头偶没有注意要声明一下函数,我之所以忽略了这个问题,那是我粗心,
函数DownRing(int n) 和函数 UpRing(int n)在各自的函数体中均有对对
方的调用,所以必须在程序的开头事先声明。

不过算法上绝对没有错误!!!
不信你再研究研究吧!!!


pengk 2002-11-05
  • 打赏
  • 举报
回复
就是递归,只不过和常见的递归不大一样。

djniulihao 2002-11-05
  • 打赏
  • 举报
回复
是递归.
lionprince 2002-11-05
  • 打赏
  • 举报
回复
九连环就是递归,我玩过的,根汉诺塔差不多
Firjest 2002-11-03
  • 打赏
  • 举报
回复
好像没那么简单,根本不是递归!!!!
pengk 2002-11-03
  • 打赏
  • 举报
回复
这是之一,还有之二吗?

33,006

社区成员

发帖
与我相关
我的任务
社区描述
数据结构与算法相关内容讨论专区
社区管理员
  • 数据结构与算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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