分糖果

Problem 16: 分糖果


Time Limit:1 Ms|  Memory Limit:128 MB
Difficulty:3

Description

童年的我们,将和朋友分享美好的事物作为自己的快乐。这天,C小朋友得到了Plenty of candies,将要把这些糖果分给要好的朋友们。已知糖果从一个人传给另一个人需要1 秒的时间,同一个小朋友不会重复接受糖果。由于糖果足够多,如果某时刻某小朋友接受了糖果,他会将糖果分成若干份,分给那些在他身旁且还没有得到糖果的小朋友们,而且自己会吃一些糖果。由于嘴馋,小朋友们等不及将糖果发完,会在得到糖果后边吃边发。每个小朋友从接受糖果到吃完糖果需要m秒的时间。那么,如果第一秒C小朋友开始发糖,第多少秒所有小朋友都吃完了糖呢?

Input

第一行为三个数n、p、c,为小朋友数、关系数和C小朋友的编号。
第二行为一个数m,表示小朋友吃糖的时间。
下面p行每行两个整数,表示某两个小朋友在彼此身旁

Output

一个数,为所有小朋友都吃完了糖的时间

Sample Input

4 3 1
2
1 2
2 3
1 4

Sample Output

5

Hint

【限制】
40%的数据满足:1<=n<=100
60%的数据满足:1<=n<=1000
100%的数据满足:1<=n<=100000
m<=n*(n-1)/2,不会有同一个关系被描述多次的情况。

【样例解释】
  第一秒,糖在1手上。第二秒,糖传到了2、4的手中。第三秒,糖传到了3的手中,此时1吃完了。第四秒,2、4吃完了。第五秒,3吃完了。所以答案是5。

分析:
用广搜把到所有点的距离求出来;最远的那个吃完那摩所有的就吃完了;
代码:
#include<stdio.h>
#include<stdlib.h>
#include<queue>
#include<vector>
using namespace std;
 
typedef struct {
    int v;
    int step;
}node;
int maxn;
queue<node> q;
vector<int> g[100010];
bool vis[100010];
 
void bfs()
{
    int i;
    node p, t;
    while(!q.empty())
    {
        p = q.front();
        q.pop();
        for(i = 0; i < g[p.v].size(); i++)
        {
            t.v = g[p.v][i];
            t.step = p.step+1;
            if(!vis[t.v])
            {
                q.push(t);
                vis[t.v] = 1;
                if(t.step > maxn)
                {
                    maxn = t.step;
                }
            }
        }
    }
}
 
int main()
{
    node t;
    int n, p,c, m, a,b,i;
    scanf("%d%d%d", &n, &p,&c);
    scanf("%d",&m);
    for(i = 0; i < p;i++)
    {
        scanf("%d%d",&a, &b);
        g[a].push_back(b);
        g[b].push_back(a);
    }
    t.v = c;
    t.step = 1;
    vis[t.v] = 1;
    q.push(t);
    bfs();
    printf("%d\n", maxn + m);
    return 0;
}


<think>好的,我现在需要解决用户关于蓝桥杯“糖果”问题的解法。用户已经提供了几个相关的引用,我需要先仔细阅读这些引用,理解各个题目的内容提供的解法,然后整理出针对“糖果”问题的有效解决方案。 首先,用户提到的引用中有两个不同的糖果问题。引用2引用5讨论的是一个糖果的循环过程,小朋友一半糖果给左手边的孩子,然后老师补发奇颗糖的孩子。而引用1、3、4似乎涉及不同的题目,比如拿糖果的动态规划贪心算法。用户的问题可能集中在引用25提到的糖果问题上,因此我需要重点关注这两个引用。 接下来,引用2中的问题描述是:每个小朋友糖果一半给左手边的孩子,完后如果有奇颗糖,老师补发1颗,直到所有孩子的糖果相同。需要计算老师补发的总糖果。引用5提到使用两个数组来处理糖过程,其中一个保存上一次的状态,以避免在更新过程中覆盖当前值。这可能涉及到模拟每一轮糖的过程,直到所有糖果相等。 我需要先明确问题的具体步骤。首先,每一轮为两个步骤:补发。糖时,每个孩子将当前糖果的一半给左边,但这里可能存在顺序问题,因为如果直接修改原组,后面的孩子糖时会使用已更新的值,导致错误。因此,需要同时保存当前上一轮的状态,或者使用临时组来处理糖过程。 例如,假设有孩子A、B、C,初始糖果为3, 5, 7。糖时,每个孩子出一半。如果直接处理,可能后面的孩子糖时前面的已经改变了。因此,正确的做法是先将所有孩子的一半糖果计算出来,然后统一配。或者使用两个数组,一个保存当前状态,另一个用来计算下一轮的状态。 引用5中提到使用两个数组,kfront组保存上一次糖后的结果,这样在糖时,每个孩子的新糖果是kfront[i]的一半加上kfront左边孩子的一半。这可能是因为糖是同时进行的,所以需要用到原来的值进行计算,而不是实时更新的值。 接下来,我需要模拟这个过程。例如,初始组为kfront,然后计算每个孩子的新糖果为kfront[i]//2 + kfront[i-1]//2(注意第一个孩子的左边是最后一个孩子),然后处理奇的情况,老师补发。这个过程需要循环直到所有孩子的糖果相同。 此外,需要注意在糖过程中,每个孩子先出自己原来的一半,所以需要先将所有孩子的出一半后的值计算出来,再配。否则,如果直接修改原组,后面的孩子糖时会使用已更新的值,导致错误。 因此,正确的步骤应该是: 1. 初始化一个组,保存当前每个孩子的糖果。 2. 循环直到所有相同: a. 创建一个临时组,保存糖后的结果。 b. 对于每个孩子i,计算临时组[i] = 原组[i] // 2 + 原组[i-1] // 2(处理第一个孩子的左边是最后一个)。 c. 检查每个临时组中的值是否为奇,如果是,补发1颗,并统计补发总。 d. 将原组更新为临时组。 3. 当所有孩子糖果相同时,结束循环,返回补发总。 在这个过程中,必须确保糖时使用的是原组的值,而不是在的过程中被修改的值,因此使用临时组是正确的做法。同时,每次糖后需要检查奇并补发,这可能会影响下一轮的糖过程。 现在,我需要考虑如何用代码实现这个逻辑。例如,使用Python的话,可以用一个循环,每次迭代处理糖、补发,并检查是否所有元素相同。 可能的代码结构如下: 初始化糖果组candies,补发总count=0 循环: 创建临时组temp,每个元素为当前元素//2 + 前一个元素//2(注意第一个的前一个是最后一个) 检查每个temp元素是否为奇,如果是,加1,count增加 检查temp中所有元素是否相等,如果是,退出循环 否则,将candies更新为temp 返回count 但这里需要注意,原组的更新应该是在所有糖操作之后,所以必须用临时组保存所有新值后再覆盖原组。 例如,对于每个孩子i的新糖果,是当前ii-1的原来值的一半相加。因此,在糖前,必须保存所有原值,或者使用一个临时组来保存中间结果。或者,在糖时,每个孩子出一半,但可能需要先计算所有孩子出去的一半,然后统一配。但根据问题描述,每个孩子一半给左边,因此每个孩子i的左边是i-1,而每个孩子i的新糖果应该是自己原来的一半(出去后剩下的)加上右边孩子给他的一半。或者可能我理解错了糖的方向? 根据引用2的描述:“每个小朋友都把自己的糖果一半给左手边的孩子。”,所以每个孩子i会出一半给左边的孩子i-1。例如,孩子i原来的糖果是a,出一半即a//2给左边,剩下的a - a//2。同时,右边的孩子i+1也会出一半给i。因此,孩子i的新糖果应该是自己剩下的部(原a - a//2)加上右边孩子给他的一半(即原i+1的糖果//2)。 但这里需要注意循环的结构,比如第一个孩子的左边是最后一个孩子。例如,个孩子0,1,2,孩子0的左边是孩子2,孩子1的左边是0,孩子2的左边是1。 因此,正确的糖过程应该是: 对于每个孩子i的新糖果,等于他自己剩下的(原i的糖果 - 原i的糖果//2)加上右边孩子给他的(原i+1的糖果//2)。或者,可能需要重新考虑糖的方向。 或者,可能每个孩子i将一半给左边,即左边的是i-1,所以i的新糖果等于他自己剩下的(原i - 原i//2)加上左边传来的糖(原i-1的//2)? 这需要明确糖的方向。比如,每个孩子i给左边(i-1),那么当糖时,每个孩子i都会给i-1自己的糖果的一半。此时,每个孩子i得到的是来自i+1的糖果的一半吗?或者,每个孩子i得到的是左边孩子i-1来的?或者这里可能我混淆了方向。 例如,孩子i给左边i-1,那么i-1得到的是i的一半。同时,孩子i-1自己给i-2,那么i得到的是i+1的一半? 这个逻辑可能需要更仔细的析。例如,假设孩子们排成一个圈,每个孩子同时一半给左边。那么,每个孩子i在糖之后的新糖果应该是他自己原来的糖果减去他出去的一半(即原i//2)加上他右边孩子给他的一半(原i+1的糖果//2)。 例如,孩子i给i-1,所以i出去原i//2,自己剩下原i - 原i//2。而同时,孩子i+1给i,因此i得到原i+1//2。因此,新的糖果是(原i - 原i//2) + (原i+1//2)。 这样,每个孩子i的新糖果取决于原i原i+1的值。因此,在糖时,必须使用原组的值,不能实时更新,否则会导致顺序问题。因此,必须使用临时组来保存新的糖果,这样每个i的新值都是基于原组的值计算的。 因此,正确的糖步骤应该是: 创建一个临时组temp,长度与candies相同。 对于每个i从0到n-1: temp[i] = (candies[i] - candies[i] // 2) + (candies[(i+1) % n] // 2) 这里,candies[i]//2是给左边i-1的,而自己剩下的部是candies[i] - candies[i]//2。然后,i得到的是右边i+1的糖果//2,因为i+1给i的是自己的糖果的一半,即candies[(i+1)%n]//2。所以,i的新糖果等于自己剩下的部加上右边来的部。 例如,假设孩子i原来的糖果是a,那么出去a//2给左边,自己剩下a - a//2。同时,右边孩子i+1原来的糖果是b,给i的是b//2。因此,i的新糖果是 (a - a//2) + b//2。 这样,temp[i]的计算是正确的。 因此,糖的正确步骤是:对于每个孩子i,计算temp[i] = (candies[i] - candies[i] // 2) + candies[next_i] // 2,其中next_i是右边的孩子,即(i+1) % n。 这样,在糖时,每个孩子的新糖果是基于原组中的值计算的,因此必须使用临时组保存所有新值,然后再替换原组。 然后,糖完成后,检查每个temp中的元素是否为奇,如果是,补发1颗,并统计补发次。例如,对于每个i,如果temp[i] % 2 != 0,则temp[i] +=1,count +=1。 之后,检查temp中的所有元素是否相同。如果是,结束循环;否则,将candies组更新为temp,继续下一轮。 因此,代码的大致流程如下: n = len(candies) count = 0 while True: # 创建临时组 temp = [] for i in range(n): give = candies[i] // 2 right = (i +1) %n receive = candies[right] // 2 new = (candies[i] - give) + receive temp.append(new) # 检查是否需要补发 for i in range(n): if temp[i] % 2 !=0: temp[i] +=1 count +=1 # 检查是否全部相同 if all(x == temp[0] for x in temp): break # 更新candies candies = temp.copy() return count 注意,在Python中,组的赋值需要深拷贝,否则可能会有引用问题。例如,candies = temp.copy() 或者使用列表生成式。 现在,我需要验证这个逻辑是否正确。例如,假设初始糖果为3,5,7: 第一糖: 每个孩子i的糖: i=0: candies[0] =3 → give=1,自己剩下2。右边是i=1,candies[1]=5→ receive=2(5//2=2)。所以temp[0] =2+2=4. i=1: candies[1]=5 → give=2,自己剩下3。右边是i=2,candies[2]=7 → receive=3(7//2=3). temp[1] =3+3=6. i=2: candies[2]=7 → give=3,自己剩下4。右边是i=0,candies[0]=3 → receive=1(3//2=1). temp[2]=4+1=5. 现在temp组是[4,6,5]。检查奇: 4是偶,6偶,5奇。所以补发1,变成5+1=6。此时temp变为[4,6,6],补发次为1。 此时组变为[4,6,6],但并非全部相同,继续下一轮。 第二糖: candies组是[4,6,6] i=0: give=4//2=2 → 剩下2。右边i=1,6→ receive 3. temp[0]=2+3=5. i=1: give=6//2=3 → 剩下3. 右边i=2,6→ receive 3. temp[1]=3+3=6. i=2: give=6//2=3 → 剩下3. 右边i=0,4→ receive 2. temp[2]=3+2=5. temp组是[5,6,5]. 检查奇: 5奇 → 补发1,变成6。补发次增加2(i=0i=2各补发一次)。此时temp是[6,6,6]. 补发次累计1+2=3. 此时所有元素相同,循环结束。总补发次为3,正确吗? 原问题可能给出的例子需要确认。例如,如果初始输入是3个孩子,糖果为3、5、7,那么老师需要补发3次,最终每个孩子有6颗。这可能正确。 因此,上述逻辑是正确的。现在,我需要将这个逻辑转化为代码,并确保正确。 此外,引用5中提到使用两个数组来处理糖过程,这可能与上述临时组的方法是一致的。例如,kfront组保存上一次的状态,用于计算当前的配。 综上所述,糖果问题的解法是模拟每一轮的补发过程,直到所有孩子的糖果相同,统计补发次。需要注意使用临时组来确保糖的正确性。</think>### 蓝桥杯“糖果”问题解法析 题目要求:$N$个小朋友围坐糖果,每轮操作中每个小朋友将一半糖果给左边的小朋友完后若某个小朋友糖果为奇,老师补发1颗。求所有小朋友糖果相同时老师补发的总次[^2][^5]。 #### 算法思路 1. **模拟糖过程**:使用临时组保存每轮调整后的状态,确保计算时使用原始据 2. **奇偶校验**:每次糖后遍历检查奇并补发 3. **终止条件**:检测所有元素是否相等时跳出循环 $$时间复杂度:O(k \cdot N),其中k为调整轮$$ #### Python代码实现 ```python def distribute_candies(candies): n = len(candies) count = 0 while True: temp = [] # 糖操作 for i in range(n): right = (i + 1) % n give = candies[i] // 2 receive = candies[right] // 2 new = (candies[i] - give) + receive temp.append(new) # 补发奇糖果 for i in range(n): if temp[i] % 2 != 0: temp[i] += 1 count += 1 # 检查终止条件 if all(x == temp[0] for x in temp): break candies = temp.copy() return count # 示例输入 print(distribute_candies([3,5,7])) # 输出:3 ``` #### 关键步骤说明 1. **糖方向处理**:每个小朋友的右边索引通过$(i+1)\%n$实现环形结构 2. **值更新策略**:糖时保留原始值的$candies[i]//2$,避免实时修改导致据污染 3. **空间优化**:使用临时组存储中间状态,空间复杂度保持$O(N)$
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值