【蓝桥杯】 历届试题 分糖果(模拟)

历届试题 分糖果

问题描述

n n n 个小朋友围坐成一圈。老师给每个小朋友随机发偶数个糖果,然后进行下面的游戏:每个小朋友都把自己的糖果分一半给左手边的孩子。一轮分糖后,拥有奇数颗糖的孩子由老师补给 1 个糖果,从而变成偶数。
反复进行这个游戏,直到所有小朋友的糖果数都相同为止。
你的任务是预测在已知的初始糖果情形下,老师一共需要补发多少个糖果。

输入格式

程序首先读入一个整数 N ( 2 < N < 100 ) N(2<N<100) N(2<N<100),表示小朋友的人数。
接着是一行用空格分开的 N N N 个偶数(每个偶数不大于 1000,不小于 2 )。

输出格式

要求程序输出一个整数,表示老师需要补发的糖果数。

样例输入

3
2 2 4

样例输出

4



—— 踏雪寻梅 ——


大多说人看到这道题的时候其实都感觉挺简单的(当然,确实不难),反正就是模拟这个分糖以及发糖的过程嘛,最后统计补发糖果的数量即可。但是,在模拟发糖过程时,便会出现一些问题。

我第一次模拟先是建立了一个 int 型数组 c h i l d s childs childs 来存储每个小朋友所拥有的糖果数量,接着通过一个循环(初始值从最后一个开始),把当前的 c h i l d s [ i ] childs[ i ] childs[i] 赋值为 c h i l d s [ i ] / 2 childs[ i ] / 2 childs[i]/2 并加上 c h i l d s [ i − 1 ] / 2 childs[ i-1 ] / 2 childs[i1]/2,即: c h i l d s [ i ] = ( c h i l d s [ i ] + c h i l d s [ i − 1 ] ) / 2 childs[ i ] = ( childs[ i ] + childs[ i-1 ] ) / 2 childs[i]=(childs[i]+childs[i1])/2,最后再为第一个小朋友单独写交换糖果的代码。

但事实是,无论 i i i 初始从 1 开始还是从最后开始,总会出错!因为小朋友们在交换时,其实是一个环形结构,因此无论从那里作为切入口进去,都将错误地把当前切入的这个小朋友的糖果数默认为 c h i l d s [ i ] / 2 childs[ i ] / 2 childs[i]/2 。而实际上,这个小朋友的糖果数量应该为 c h i l d s [ i ] / 2 + c h i l d s [ i − 1 ] / 2 childs[ i ] /2 + childs[ i-1] / 2 childs[i]/2+childs[i1]/2(或者为 c h i l d s [ i ] / 2 + c h i l d s [ i + 1 ] / 2 childs[ i ] /2 + childs[ i+1] / 2 childs[i]/2+childs[i+1]/2)。

并且仔细一点的同学应该发现了,在循环中,当你执行完了某次 c h i l d s [ i ] = ( c h i l d s [ i ] + c h i l d s [ i − 1 ] ) / 2 childs[ i ] = ( childs[ i ] + childs[ i-1 ] ) / 2 childs[i]=(childs[i]+childs[i1])/2 后,对于下一次而言,其实这时的 c h i l d [ i ] child[ i ] child[i] 已经不再是初始的那个 c h i l d s [ i ] childs[ i ] childs[i] 了(当然, c h i l d s [ i − 1 ] childs[ i-1 ] childs[i1] 也类似)。因为当你的代码用到了这样的一个循环的时候,说明你已经默认这个分糖果的游戏是按序轮次一个一个进行的,而实际上,这个发糖的过程是所有小朋友同时开始分、发、接受的!(当然,理解错误有一部分是题目表意不明的原因)。

既然是同时发糖的,那么为何不多用两个数组来维护这个发糖的过程呢?因此,修正后的解题思路大致如下:

  • 步骤一:用一个数组 c h i l d s [ i ] childs[i] childs[i] 来存储初始情况下每个小朋友手上的糖果数,并建立两个数组 c l d 1 [ i ] cld1[i] cld1[i] c l d 2 [ i ] cld2[i] cld2[i] 用以维护之后的游戏过程。
  • 步骤二:模拟发糖过程(这是一重循环,结束条件即为所有小朋友的糖果都相同):
    • 通过一重循环将所有小朋友的糖果都除以 2 ,并将结果保存进入 c l d 1 [ i ] cld1[i] cld1[i] 中;
    • 通过一重循环把每个小朋友手上的糖果错位存储进 c l d 2 [ i ] cld2[i] cld2[i] 中(注:首位小朋友需要单独错位,即 c l d 2 [ 0 ] = c l d 1 [ N − 1 ] cld2[0]=cld1[N-1] cld2[0]=cld1[N1]);
    • 更新每个小朋友手上的糖果数量,即 c h i l d s [ i ] = c l d 1 [ i ] + c l d 2 [ i ] childs[i]=cld1[i]+cld2[i] childs[i]=cld1[i]+cld2[i]


—— 破云见雾 ——


下面给出基于以上思路的完整代码:

#include<iostream>
using namespace std;
int main()
{
	int N,i,childs[100],sum=0;
	int cld1[100],cld2[100];
	cin>>N;
	for(i=0;i<N;i++)
		cin>>childs[i];
	while(1)
	{
		//二分处理
		for(i=0;i<N;i++)
			cld1[i]=childs[i]/2;
		for(i=1;i<N;i++)
			cld2[i]=cld1[i-1];
		cld2[0]=cld1[N-1];

		//合同处理
		for(i=0;i<N;i++)
			childs[i]=cld1[i]+cld2[i];
		int flag=childs[0];
		for(i=1;i<N;i++)
			if(childs[i]!=flag)
				break;

		//再次发糖
		if(i!=N)
		{
			for(i=0;i<N;i++)
				if(childs[i]%2!=0)	//检测到需要发糖
				{
					childs[i]++;
					sum++;
				}
		}
		
		//退出
		else break;
	}
	cout<<sum<<endl;
	return 0;
}



END


评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

theSerein

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

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

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

打赏作者

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

抵扣说明:

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

余额充值