PTA:7-28 猴子选大王 (20分)

博主不定期更新【保研/推免、C/C++、5G移动通信、Linux、生活随笔】系列文章,喜欢的朋友【点赞+关注】支持一下吧!


文章目录


  一群猴子要选新猴王。新猴王的选择方法是:让N只候选猴子围成一圈,从某位置起顺序编号为1~N号。从第1号开始报数,每轮从1报到3,凡报到3的猴子即退出圈子,接着又从紧邻的下一只猴子开始同样的报数。如此不断循环,最后剩下的一只猴子就选为猴王。请问是原来第几号猴子当选猴王?

输入格式:
  输入在一行中给一个正整数N(≤1000)。

输出格式:
  在一行中输出当选猴王的编号。

输入样例:

11

输出样例:

7

思路1

  以输入样例N=11为准,列出完整其淘汰过程,寻找规律(在能找到规律的前提下,也可以将N设的更小一点):

初始值1234567891011
第一轮后910×12345678
第二轮后67×89×12345
第三轮后34×56×78×12
第四轮后×1×23×45×67
第五轮后×5×6××12×34
第六轮后×2×3××45××1
第七轮后×4××××12××3
第八轮后×1××××23×××
第九轮后×1××××2××××
第十轮后××××××1××××

  依据题意,每次报数为3的猴子被淘汰,之后更新所有猴子序号,继续进行,整个过程如上表所示。每一轮淘汰一只猴子,因此共需要N-1轮,即可选出猴王。下面来看一下淘汰过程中,序号的更新规律:淘汰序号为3的猴子后,原队列中序号大于3的猴子,序号-3;原队列中序号小于3的猴子,序号+(N-3),且N每轮结束后要递减。我们依据此规律编写代码,有以下需注意的点:
  1. 当进入倒数第二轮(即第N-2轮)时,序列中只有两个序号,1和2,此时不能再以序号=3作为出局的判断条件;而观察数据可以发现,在第N-3轮时,剩余的三个猴子中,序号为2的便是最终的获胜者,因此,为了每次淘汰的条件一致,我们只进行N-3轮淘汰,而在剩下的3个猴子中,序号为2的便是猴王;
  2. 由于我们要进行N-3轮淘汰,因此当N=1,2或3时,无法进行淘汰,而根据之前制定的序号为2即是猴王的规则,我们发现,N=2和3时,都恰好能给出正确答案,而N=1时输出为空,因此,对于N=1的特殊情况,我们单独列出;
  3. 对于其中被淘汰的猴子,暂时没有想到什么好的方法来表示,这里给每个被淘汰的猴子序号赋值为-1000000(即最大N×N的相反数),以确保经过循环的运算,不会对输出结果造成影响;

#include <stdio.h>

int main()
{
	int N;
	scanf("%d", &N);
	int n=N; //由于每轮判断需要对N进行递减,在此我们保留原始N值,做循环以及输出用
	int a[N];
	int i;
   /*读入猴子序号*/
	for (i=0; i<N; i++)
	{
		a[i]=i+1;
	}
   /*进行N-3轮淘汰*/
	int j;
	for (j=1; j<=n-3;j++)
	{
		for (i=0; i<n; i++)
		{
			if (a[i] == 3) //每轮淘汰以序号是否=3作为判断条件
			{
				int t=0;
		    /*按更新规律对序号进行更新*/
				for (t=0; t<n; t++)					
				{
					if (a[t]<a[i])
					{
						a[t] = a[t] + N-a[i]; 
					}
					else if (a[t]>a[i])
					{
						a[t] = a[t] - a[i];
					}
				}
/*每一轮更新完成后,将淘汰猴序号设为如下,N递减,跳出内层循环,进行下一轮淘汰*/
				a[i] = -1000000;
				N--;
				break;
			}
		}	
	}
/*N=1特殊情况,单独输出*/	
	if ( n==1 )
	{
		printf("%d\n", n);
	}
/*N=2和3时,原本也应单独输出,但考虑到与以下循环结果一致,因此不单独给出*/
/*N-3(N>3)轮淘汰后,剩下的3只猴子中,序号2为猴王*/
	for (i=0; i<n; i++)
	{
		if (a[i] == 2)
		{
			printf("%d\n", i+1);//猴子序号等于数组下标+1
		}
	}
	return 0;
}

思路2

  以上解法中淘汰过程中直接用猴子的序号作为判断依据,每次淘汰完都需要对每个猴子的序号进行更新,且被淘汰的猴子序号不知道如何处理,方法较为复杂,更像是在做数学题而不是编程题。下面给出更简单直观的方法,引入两个计数变量第一个变量作为淘汰变量,每数到3淘汰一个,重新计数;第二个变量作为剩余变量,记录剩余猴子数,每淘汰一个减少1,当剩余变量为1时,结束,代码如下:

#include <stdio.h>

int main()
{
	int N;
	scanf("%d", &N);
	int a[N];
	int i;
	for (i=0; i<N; i++)
	{
		a[i]=i+1;
	}
	
	int elimination = 0; //淘汰变量 
	int remainder = N; //剩余变量 
	while (remainder > 1)
	{
		for (i=0; i<N; i++)
		{
			if (a[i] == 0) 
			{
				continue; 
			}
			//序号为0的猴已淘汰,不计数,直接进入下一轮循环 
			elimination++;
			if (elimination == 3)
			{
				a[i] = 0; //淘汰之后的猴子序号设为0 
				elimination = 0; //淘汰变量重置 
				remainder--; //剩余猴数减1 
			}
		}
	}
	for (i=0; i<N; i++)
	{
		if (a[i] != 0)
		{
			printf("%d\n", i+1);
		}
	}
	return 0;
}
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

月半 月半

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值