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

文章目录

  前言:这道题是女朋友之前校招的一道笔试题,当时我还不会做,现在刷题碰巧刷到,在此记录一下自己的解法。

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

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

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

输入样例:

11

输出样例:

7

思路1

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

初始值 1 2 3 4 5 6 7 8 9 10 11
第一轮后 9 10 × 1 2 3 4 5 6 7 8
第二轮后 6 7 × 8 9 × 1 2 3 4 5
第三轮后 3 4 × 5 6 × 7 8 × 1 2
第四轮后 × 1 × 2 3 × 4 5 × 6 7
第五轮后 × 5 × 6 × × 1 2 × 3 4
第六轮后 × 2 × 3 × × 4 5 × × 1
第七轮后 × 4 × × × × 1 2 × × 3
第八轮后 × 1 × × × × 2 3 × × ×
第九轮后 × 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;
}
发布了54 篇原创文章 · 获赞 100 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_43871127/article/details/104365027