c语言的基本案例猴子,[转载]猴子选大王问题(C语言实现)

题目大概是这样的:

n只猴子(n不超过50)围成一个圈。从某一只开始依次给猴子们编号,从1到n。然后从第一只猴子开始,从1开始依次报数,报到m的猴子离开圈子。从这只离开的猴子的下一只开始再从1开始报数,报到m的再离开。以此类推,直到最后剩下一只猴子为止。这只剩下的猴子就是大王。现在编写程序,输入n和m,输出大王的号码。

举个例子,假设n等于4,m等于三。最开始圈子里面有4只猴子:

1 2 3 4

从1号猴子开始报数,报到3的猴子离开。于是现在剩下的猴子是:

1 2 4

然后从4号猴子报1,1号猴子报2,2号猴子报3离开。于是剩下:

1 4

然后从4号猴子报1,1号猴子报2,4号猴子报3离开。这样剩下一只1号猴子就是大王。

这种解决问题的方法叫模拟。如果数字小,可以手工模拟。如果数字大,让人来做模拟,工作量太大,而且容易出错。但是计算机最擅长解决这样的单调重复的问题了,所以我们编个程序来模拟这个过程。

首先先想一下如何模拟这个站在圈子里和离开圈子的过程。我们可以申请一个数组,数组的一号下标代表一号猴子,50号下标代表50号猴子。由于题目中限定猴子不会超过50只,所以只要声明长度为51的数组就够了。C语言里面的数组下标是从0开始的,零号我们弃置不用,最多从1号使用到50号下标。在报数之前把数组有猴子的部分初始化成都是1.用1代表这只猴子还在圈里。如果这只猴子离开圈子,就把数组这个格子写入0.这样,刚才我们说的模拟过程就可以用数组表示成这样:

最开始:第一行表示数组下标,第二行表示数组里面的值。只写出0到4号下标的情况,后面全是0省略不写。

0 1 1 1 1

第一轮报数之后:

0 1 2 3 4

0 1 1 0 1

第二轮报数之后:

0 1 2 3 4

0 1 0 0 1

第三轮报数之后:

0 1 2 3 4

0 1 0 0 0

于是还剩下1号是1,那么一号猴子就是大王。

那么,这个程序的思路就是:

读入n和m

把数组的1到n号下标赋值成1

报数n-1次,报数的时候维护数组,把合适的位置写成0

找到数组里面剩下的唯一不是0的位置。把这个位置的下标输出。

下面我们把注意力集中在如何报数和维护数组的问题上。为了方便起见先编写两个小函数。

第一个函数的名字叫succ,给它一个数字,它返回这个参数在这个圈子里面的下一个数。就是说,如果n等于10,你给它7它就返回8,你给它8它就返回9.但是,注意,如果你给它10,它会返回1.这样,就相当于用这个函数实现了循环数组。一旦你数到了数组的结尾,那就自动再从开头开始数。这样的函数是不是很好写啊。

{

if(t==n)

return

1;

return

t+1;

}

注意两个问题。第一,这个n是全局变量,就是定义在所有函数外面,所有函数公用的变量。第二,可能有人问我为什么这个if语句不用else。仔细分析一下,如果t和n相等,那么就直接返回1,结束了,就不会执行return

t+1这句话。如果能执行到return

t+1,就说明前面的t==n的条件不成立。所以这里面不需要else。当然,如果你写成这样也是等价的:

int succ(int t)

{

if(t==n)

return

1;

else

return

t+1;

}

下一个函数是给它一个数字,它返回从这个位置往后,下一个在圈子里的猴子的号码。先贴代码,然后解释:

int nextMonkey(int t)

{

int

i;

i=succ(t);

while(a[i]!=1)

i=succ(i);

return

i;

}

首先通过i=succ(t);这句话,找到t开始下一只猴子的位置(不管这一只在不在圈子里),然后判断循环,如果a[i]!=1,就是说这一只已经离开圈子了,那么i=succ(i),再找下一只猴子。就这样循环,知道找到一只在圈子里的为止。这样,就找到了从t后面开始第一只在圈子里的猴子,这只猴子的号码是i。于是返回i就可以了。

有了这两个函数做铺垫,是不是一切简单多了?我把完整代码贴上来,然后简单解释一下:

int succ(int t);

int nextMonkey(int t);

int n,m;

int a[51];

int main(void)

{

int

i,j,p;

scanf("%d%d",&n,&m);

for(i=1;i<=n;i++)

a[i]=1;

p=1;

for(i=1;i

< n;i++)

{

for(j=0;j

< m-1;j++)

{

p=nextMonkey(p);

}

a[p]=0;

p=nextMonkey(p);

}

printf("%d",p);

return

0;

}

int succ(int t)

{

if(t==n)

return

1;

return

t+1;

}

int nextMonkey(int t)

{

int

i;

i=succ(t);

while(a[i]!=1)

i=succ(i);

return

i;

}

首先,这个程序里面n、m和数组a都是全局变量。这样,程序里面的这几个函数都可以用它们。从main函数开始,先读入n和m,然后用一个循环语句,把数组里面从1到n的格子都赋值为1,表面开始的时候所有猴子都在圈子里。然后p赋值为1,表示现在从第一号猴子开始报数。

然后进入一个两重循环,外层用i控制,循环n-1次,代表n-1次报数。里层先循环m-1次,用j控制,每次都向后数一个还在圈子里的猴子。这样,当m-1次循环结束之后,我们找到了不幸的报到m号的猴子,这只猴子的号码是p。于是把p位置清零,然后往后找一只猴子,继续下一次报数。当外层循环结束的时候,剩下一只,号码就是p了,于是把p输出。

有两个问题我没有说具体。为什么里层循环是m-1次而不是m次?为什么外层循环结束的时候剩下的大王号码就是p?自己好好思考哦。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值