30个猴子站成一圈,从第一只猴子开始数到第三只猴子时,第三只猴子出圈;接着从第四只数,第六只猴子出圈…
按此规律,最后出圈的一个为猴王
此问题可用回溯算法求解
#include <stdio.h>
#include <stdlib.h>
#define MAX 30
int monkey[MAX];
void init()
{
int i;
for(i=0;i<=MAX-1;i++)
{
monkey[i]=i+1;
printf("%d ",monkey[i]);
}
}
void output()
{
int i;
printf("\n\n猴子淘汰出圈的顺序是:\n");
for(i=MAX-1;i>=0;i--)//数组最后的元素是第一个淘汰出圈的猴子
printf("第%3d只猴子出圈!\n",monkey[i]);
printf("猴王是第%3d只猴子!\n",monkey[i+1]);
}
int main()
{
init();
int i,j,k,temp;
for(i=MAX-1;i>=0;i--)//经过上一轮循环monkey[i]=temp之后,上一轮循环得到的最末尾元素不再参与循环
{
for(k=1;k<=3;k++)//每次回溯三个值
{
temp=monkey[0];//先保存此时第一个元素的值
for(j=0;j<i;j++)
{
monkey[j]=monkey[j+1];//元素向前推移(并非所有元素向前推移)
}
monkey[i]=temp;//最后一个元素变成循环开始时第一个元素的值
}
}
output();
return 0;
}
下面拿9只猴子来说明一下代码
经过init函数猴子站成一圈:1 2 3 4 5 6 7 8 9
(注:为了方便观看,出圈的猴子用“#”以及删除线表示)
经过第一次循环(一次循环回溯三个值)后,数组变为:
4 5 6 7 8 9 1 2 #3
在第二次循环时,最末尾的3永远不再参与回溯,数组变为:
7 8 9 1 2 4 5 #6 3
第三次循环时,末尾的3和6不参与回溯,数组变为:
1 2 4 5 7 8 #9 6 3
第四次循环,3,6,9不参与回溯,数组变为:
5 7 8 1 2 # 4 9 6 3
第五次循环,数组变为:
1 2 5 7 #8 4 9 6 3
第六次循环,数组变为:
7 1 2 #5 8 4 9 6 3
第七次循环,数组变为:
7 1#2 5 8 4 9 6 3
(在第七次循环后剩下的猴子只剩下两个,为了方便最后一次循环,可以将数组写为:7 1 7 1#2 5 8 4 9 6 3)
第八次循环,数组变为:
1 7 1# 7 2 5 8 4 9 6 3
因为在第七次循环中多加了一个 7 1,去掉一个“7 1” 只剩下了 1,所以最后的数组变为:1 # 7 2 5 8 4 9 6 3
那么猴王就是第1个了
当然,为了方便说明代码只是用来9只猴子选大王,所以在下面输出30只猴子选大王的结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
猴子淘汰出圈的顺序是:
第 3只猴子出圈!
第 6只猴子出圈!
第 9只猴子出圈!
第 12只猴子出圈!
第 15只猴子出圈!
第 18只猴子出圈!
第 21只猴子出圈!
第 24只猴子出圈!
第 27只猴子出圈!
第 30只猴子出圈!
第 4只猴子出圈!
第 8只猴子出圈!
第 13只猴子出圈!
第 17只猴子出圈!
第 22只猴子出圈!
第 26只猴子出圈!
第 1只猴子出圈!
第 7只猴子出圈!
第 14只猴子出圈!
第 20只猴子出圈!
第 28只猴子出圈!
第 5只猴子出圈!
第 16只猴子出圈!
第 25只猴子出圈!
第 10只猴子出圈!
第 23只猴子出圈!
第 11只猴子出圈!
第 2只猴子出圈!
第 19只猴子出圈!
第 29只猴子出圈!
猴王是第 29只猴子!!