首页 > 试题广场 >

糖果谜题

[编程题]糖果谜题
  • 热度指数:6454 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32M,其他语言64M
  • 算法知识视频讲解
小明是幼儿园的一名老师。某天幼儿园园长给小朋友们每人发一颗糖果,小朋友们拿到后发现有一些同学拿到的糖果颜色和自己相同,有一些同学糖果颜色和自己不同。
假定每个小朋友只知道有多少同学和自己拿到了相同颜色的糖果。
上课后,有一部分小朋友兴奋的把这一结果告诉小明老师,并让小明老师猜一猜,最少有多少同学拿到了糖果。
例如有三个小朋友告诉小明老师这一结果如下:
其中第一个小朋友发现有1人和自己糖果颜色一样,第二个小朋友也发现有1人和自己糖果颜色一样,第三个小朋友发现有3人和自己糖果颜色一样。
第一二个小朋友可互相认为对方和自己颜色相同,比如红色;
第三个小朋友不可能再为红色(否则第一二个小朋友会发现有2人和自己糖果颜色相同),假设他拿到的为蓝色糖果,那么至少还有另外3位同学拿到蓝色的糖果,最终至少有6位小朋友拿到了糖果。
现在请你帮助小明老师解答下这个谜题。

输入描述:
假定部分小朋友的回答用空格间隔,如 1 1 3


输出描述:
直接打印最少有多少位小朋友拿到糖果
如 6
示例1

输入

1 1 3

输出

6
示例2

输入

0 0 0

输出

3

说明

三位小朋友都没发现有人和自己的颜色相同,所以最少的情况就是三位小朋友糖果的颜色均不同

备注:
其中回答学生个数最多1000
每个学生回答的答案在[0,999]之间
哪些测试没通过也不显示一下!
发表于 2018-07-31 14:56:42 回复(2)
#include<bits/stdc++.h>
usingnamespacestd;
int main()
{
    vector<int> nums;
    int t;
    while(cin>>t)
    nums.push_back(t);
    map<int,int> mp;  //mp[i] 记录有多少种“i个人跟自己相同”情况,可变
    int res = 0;
    for(inti = 0;i<nums.size();i++)
    {
        if(mp.find(nums[i]) == mp.end()) //如果还没有出现“nums[i]个人跟自己相同”这种情况,则map[i]=1,总数+=nums[i]+1,最后的1是加上自己的数量
        {
            mp[nums[i]] = 1;
            res+=nums[i]+1;
        }
        else if(mp[nums[i]]<=nums[i])//已经有重复的情况则检测mp[nums[i]]是否超过了nums[i]个,如果还没则+1,然后总数不变
        {
            mp[nums[i]]++;
        }
        else  //已经有重复的情况并且总数也加完之前重复的情况了,所以map[i]需要重新开始计算
        {
            mp[nums[i]] = 1;
            res+=nums[i]+1;
        }
    }
    cout<<res<<endl;
    return0;
}

编辑于 2018-08-02 20:48:13 回复(0)
相同糖果数目的可以看成一个圈子,圈子里的人数为糖果数目+1,求出相同糖果数目的人最少要组成几个圈子
import sys

nums = list(map(lambda x: int(x), sys.stdin.readline().strip().split(" ")))
groups = [[i, nums.count(i)] for i in set(nums)]
res = 0
for group in groups:
    people_num = group[0] + 1
    m = int(group[1] / people_num)
    n = group[1] % people_num
    if(n!=0):
        m+=1
    res += people_num * m
 
print(res)

编辑于 2019-05-10 11:14:27 回复(0)
利用哈希表做,记录相同数字长度,
当长度大于数字值的时候,累计值加一的值,并更新该值的长度
当值小于长度,累计值加一
#include<iostream>
#include<unordered_map>
#include<vector>
usingnamespacestd;
intmain()
{
    inttemp;
    unordered_map<int,int> m;
    while(cin>>temp)
    {
        m[temp]++;
    }
    intres = 0;
    for(auto iter = m.begin();iter!=m.end();iter++)
    {
        intval = iter->first;
        intnum = iter->second;
        while(num>val)
        {
            res += val+1;
            num = num - val -1;
        }
            if(num == 0)
                continue;
            else
            res += (val+1);
    }
    cout<<res<<endl;
     
}

发表于 2018-08-02 22:11:37 回复(0)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;

//总结目前牛客问题 第一,没有循环输入问题, 第二 有循环输入问题, 第三 输入有多余空格问题 ,第四 中间插入多余空行问题 ....
namespace Test0001
{
    class Program
    {
        public static void Main(string[] args)
        {
            //string line;
            //while (!string.IsNullOrEmpty(line = Console.ReadLine())) Func(line);
            Func(Console.ReadLine());
        }
        public static void Func(string line)
        {
            var s1 = line.Trim().Split(' ').Select(x => int.Parse(x)).GroupBy(x => x).Select(x => new { val = x.Key, count = x.Count() }).ToArray();
            int sum = 0;
            foreach (var item in s1)
            {
                int n = (item.count + item.val) / (item.val + 1);
                sum += (item.val + 1) * n;
            }
            Console.WriteLine(sum);
        }
    }
}
//这道题想明白其实很简单的
首先 11 2 3333 44444 4
1个人和我有一样颜色的苹果,这句话表示至少2个人参与.并且把这2人看做一个组
这样 1和1可以组成一个人数为2的组  222 可以组成一个人数为3的组 当不足222是 只要有一个2 也按 222来算,同理 3333 组成一个人数为4的组, 如果不足也按4来算 如果超过4个 就组成2个组因此是8人
所以 先把所以数据分组 相同的为一组,并且统计个数
那么他可以组成多少个组 (他的个数)/(他的值+1)并且向上取整  等同于 (他的个数+他的值)/(他的值+1)
每组都需要 他的值+1个 因此 最后的值sum累加上 组数 * (他的值+1)即为最后最少的人数

编辑于 2019-12-11 10:36:21 回复(0)
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;


public class Main {

    public static void main(String[] args) throws IOException {
        BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
        String[] line1 = bf.readLine().split(" ");
        int n = line1.length;
        //记录相同回答的人的个数
        HashMap<Integer, Integer> map = new HashMap<>();
        for (int i = 0; i < n; i++) {
            int a = Integer.parseInt(line1[i]);
            map.put(a, map.getOrDefault(a, 0) + 1);
        }
        int sum = 0;
        /**
         * 解释一下:map = < a , 1 >,则这里至少有 a + 1 个小朋友
         *         map = < a , count>,当count大于1时候
         *         假如 a = 5,count = 4, 则至少有 5 + 1 个人,这四个人都拿同样的颜色,另外还有两个人个人也拿一样
         *         假如 a = 5,count = 5, 则至少有 5 + 1 个人,这五个人都拿同样的颜色,另外还有一个人也拿一样
         *         假如 a = 5,count = 6, 则至少有 5 + 1 个人,这六个人都拿同样的颜色,不存在另一个人
         *         假如 a = 5,count = 7, 则至少有 (5 + 1)*2 个人
         *         七个人中,6个人拿一样,剩下一个人肯定不能拿一样颜色了,那么最后一个人是单独的 即和< a,1> 一样的道理
         *         你把7个人分成两组,其实答案也是一样的,需要  (a+1)*2
         * 综上分析:
         *          每 a+1个人包括 a+1,都是 a+1个人
         *          可以理解为 7/6 余 1,需要 2倍的 a + 1
         *          直接 (count + a)/(a+1)就相当于向上取整了
         */
        for (Integer a : map.keySet()) {
            sum += ((map.get(a) + a) / (a + 1)) * (a + 1);
        }
        System.out.println(sum);
    }
}
发表于 2019-08-06 17:25:52 回复(1)
//只有相同的数才有可能是同一种颜色的糖果,并且相同的数出现的次数大于该数+1(包括它本身),
//则一定又是一种新颜色,所以思路是用map记录数字出现的次数,为0则说明刚出现或者次数用尽,
//可以累计

#include<iostream>
#include<unordered_map>
using namespace std;
int main()
{
	int num,res=0;
	unordered_map<int, int> a;
	while (cin >> num)
	{
		if (a[num] == 0)
		{
			a[num] = num;
			res += num + 1;
		}
		else
			a[num]--;
	}
	cout << res << endl;
	return 0;
}


发表于 2019-08-06 11:28:12 回复(0)
 用得比较笨的方法做的,假设小朋友发现有N人和自己糖果颜色一样,在这些小朋友***有M个人说过发现有N人和自己糖果颜色一样。例如甲、乙、丙、丁小朋友告诉老师,有2个人的糖果颜色和他相同。
可得N=4,M=2。
对给的数组进行整理,new一个Hashmap,key为N,value为M,示例1就可以整理为{key=1,value=2;key=3,value=1}。示例2就可以整理为{key=0,value=3},接下来就可以对经过预处理后的数据进行分情况讨论:
1.如果N=0,那说明所有小朋友中他拥有的颜色唯一,则M为多少,最少人数就直接加M。
2.如果N != 0,那又有两种情况: 
  ①M<=N+1,那最少人数就加N。(很好理解,有5个小朋友都告诉过老师,有其他4个小朋友和他颜色一样,那最少人数就是5,因为每个告诉老师的小朋友也要把他自己算进去哦)
  ②M>N+1 那最少人数加N+1,M=M-N-1,然后继续重复 2 过程(不是②(本质上就是①的延续,假如有10个小朋友都告诉过老师,有其他4个小朋友和他颜色一样,那最最极限的情况就是,有两拨拥有不同颜色的小朋友,每一拨各五人
下面是实现代码
import java.io.*;
import java.util.*;

public class Main{
    public static void main(String[] args) throws IOException{
        int result = 0;
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        HashMap < String, String> hashmap = new HashMap < String, String>();
        String[] s = br.readLine().split(" ");
        for(int i = 0 ;i<s.length;i++){
            if(hashmap.containsKey(s[i])){
                Integer temp = Integer.parseInt(hashmap.get(s[i]));
                temp++;
                hashmap.put(s[i],Integer.toString(temp));
            }
            else{
                hashmap.put(s[i],Integer.toString(1));
            } 
            
        }
           for (String key : hashmap.keySet()) {
    
            int tempKey = Integer.parseInt(key);
            int tempValus = Integer.parseInt(hashmap.get(key));
            if(tempKey==0){
                result += tempValus;
            }
            else{
                while(tempValus-tempKey-1>0){
                    result += tempKey+1;
                    tempValus -= tempKey;
                }
                result += tempKey+1;
            }
    }
         System.out.print(result);
}
}


发表于 2021-09-14 14:41:18 回复(0)
某个小朋友回答x,则算上他自己至少有x+1个小朋友是同一个颜色的糖果。如果有y个小朋友回答x,则y个小朋友一共持有ceil(y/(x+1))种颜色的糖果,每种颜色的糖果x+1人持有(此时人数是最少的)。因此对于这一组(x,y),至少有ceil(y/(x+1))*(x+1)个小朋友,对回答的数目进行计数,对每组键值对都进行这样的计算即可。
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.util.HashMap;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String[] strArr = br.readLine().trim().split(" ");
        int[] arr = new int[strArr.length];
        HashMap<Integer, Integer> counter = new HashMap<>();
        for(int i = 0; i < strArr.length; i++) {
            arr[i] = Integer.parseInt(strArr[i]);
            if(counter.containsKey(arr[i])){
                counter.put(arr[i], counter.get(arr[i]) + 1);
            }else
                counter.put(arr[i], 1);
        }
        int count = 0;
        for(int x: counter.keySet()){
            int y = counter.get(x);
            count += (x + y)/(x + 1)*(x + 1);
        }
        System.out.println(count);
    }
}

编辑于 2021-04-05 13:28:50 回复(0)
d = input()
data = d.split()
data_set = set(data)
n = len(data)
for each in data_set:
    item = int(each)
    if data.count(each) % (item + 1):
        n += item + 1 - (data.count(each) % (item + 1))
print (n)
这道题的重点应该放在需要额外添加多少人才能跟这些小朋友匹配完全,故只需求出各数量的小朋友差多少人能完全匹配就行了
编辑于 2021-02-28 19:12:46 回复(0)

21行代码

#include<stdio.h>
#include<unordered_map>
using namespace std;
int main(){
    unordered_map<int,int> mp;
    int t,sum=0,k;
    while(~scanf("%d",&t)){
        mp[t]++;
    }
    for(auto q:mp){
        if(q.first<q.second-1){
            k=q.first+1;
            while(k<q.second){
                k+=q.first+1;
            }
            sum+=k;
        }
        else sum+=q.first+1;
    }
    printf("%d",sum);
}
编辑于 2021-01-18 16:27:03 回复(0)
import math
v=list(map(int,input().split()))
v.sort()
count=0
i=0
while i <len(v):
    n=v.count(v[i])
    count=count+math.ceil(n/(v[i]+1))*((v[i]+1))
    i=i+n
print(count)

发表于 2020-05-26 10:38:09 回复(0)
不是很复杂吧。。。

#include<bits/stdc++.h>
using namespace std;

const int MAXN = 1e3+1;

int cnt[MAXN];
int main(){
    int n;
    int M=0,sum=0;
    while(cin>>n){
        cnt[n]++;
        M=max(n,M);
    }
    for(int i=0;i<=M;i++){
        int num=cnt[i]%(i+1)?cnt[i]/(i+1)+1:cnt[i]/(i+1);
        sum+=(i+1)*num;
    }
    cout<<sum<<endl;
    return 0;
}

发表于 2020-05-13 18:04:51 回复(0)
from collections import defaultdict
a = defaultdict(int)
b = list(map(int,input().split()))
for i in b:
    a[i] += 1
res = []
for i,j in a.items():
    tmp = j//(i+1)
    if j%(i+1) != 0:
        tmp += 1
    res.append(tmp*(i+1))
print(sum(res))
思路就是用一个字典存储每个数字的次数,然后遍历这个字典,计算每个数实际上的出现的次数,然后将所有结果相加,就是最后的结果。
发表于 2020-04-14 18:15:36 回复(0)
#include <bits/stdc++.h>
using namespace std;

int main(){
    int x,s=0;
    vector<int> v;
    map<int,int> m;
    while(cin>>x)
        v.push_back(x);
    int n = v.size();
    for(int i=0;i<n;i++){
        if(m.find(v[i])==m.end()){
            m[v[i]] = 1;
            s += v[i]+1;
        }else if(m[v[i]]<=v[i])
            m[v[i]]++;
        else{
            m[v[i]] = 1;
            s += v[i]+1;           
        }
    }
    cout<<s<<endl;
    return 0;
}

发表于 2019-11-22 01:24:53 回复(0)
代码写的有点丑…………
这道题还比较有趣,思路重点就是:
1.相同的合并直至达到对应人数。
2.不相同的独立对应一个人数。
3.相同的超出对应人数,则新对应一个人数。
#include<iostream>
#include<vector>
#include<utility>
#include<algorithm>
using namespace std;

int main()
{
    vector<int> input;
    int tmp;
    while(cin>>tmp)
    {
        input.push_back(tmp);
        if(cin.get()=='\n')
            break;
    }
    int n=input.size();
    int j;
        //辅助数组
    vector<pair<int,int> > aux(n);
    vector<int>::iterator it;
    //aux[0].first=input[0]+1;
    //aux[0].second=1;
    for(int i=0;i<n;i++)
    {
                //不相同
        if((it=find(input.begin(),input.begin()+i,input[i]))==(input.begin()+i))
        {
            aux[i].first=input[i]+1;
            aux[i].second=1;
        }
                //相同
        else{
            j=it-input.begin();
                        //相同的要找:最近的 
            while((it=find(it+1,input.begin()+i,input[i]))!=(input.begin()+i))
            {
                if(aux[it-input.begin()].first==input[i]+1)
                    j=it-input.begin();
            }
                        //人数未满
            if(aux[j].second<aux[j].first)
            {
                aux[j].second+=1;
            }
                        //人数已满
            else{
                aux[i].first=input[i]+1;
                aux[i].second=1;
            }
        }
    }
    int num=0;
    vector<pair<int,int> >::iterator it1=aux.begin();
    for(;it1<aux.end();it1++)
    {
        if(it1->first!=0)
            num+=it1->first;
    }
    cout<<num;
    
}

发表于 2019-10-18 17:04:02 回复(0)
#include<iostream>
#include<string>
#include<vector>
using namespace std;
int main() {
	vector<int> v1;
	string str;
	getline(cin,str);
	int num = 0;
	int max = 0;
	for (int i = 0; i <= str.size(); i++) {
		if (str[i] != ' ' && str[i] != NULL) {
			num = num * 10 + str[i] - '0';
			continue;
		}
		v1.push_back(num);
		max = max > num ? max : num;
		num = 0;
	}
	vector<int> v2(max + 1, 0);
	for (int i = 0; i < v1.size(); i++)
		v2[v1[i]]++;
	int total = 0;
	for (int i = 0; i < v2.size(); i++) {
		int t = v2[i] / (i + 1);
		if (v2[i] % (i + 1) != 0) {
			total += i + 1;
		}
		total += t*(i + 1);
	}
	cout << total << endl;
}
提醒一下和我一样没看清题的同学hhhhhh,题目规定了输入的范围如下,不需要做成变长:
其中回答学生个数最多1000
每个学生回答的答案在[0,999]之间

编辑于 2019-09-12 02:17:08 回复(0)
"""
思路:看相同的数字a可以构成几个团块,每个团块的最多数量是a+1
1.哈希计算数字的个数
2.遍历哈希表,假设2的个数5,即:222 22;前3个2可以构成一个团,后面两个2可以构成一个团,
每个团最多2+1个小朋友,所以共有6个;团个数可用除法和求余的方法计算
3.累加每个数字计算得到最终结果
"""
import sys

nums = list(map(int, input().strip().split()))

hashlist = {}
for num in nums:
    hashlist[num] = hashlist.get(num, 0) + 1

res = 0
for key, val in hashlist.items():
    tmp = val // (key+1)
    res += tmp*(key + 1) if val % (key+1) == 0 else (tmp+1)*(key+1)
print(res)

发表于 2019-09-06 21:52:07 回复(0)

思想就是用map记录每个相同数字num的次数count;
1、count<=num+1,则该num对应的人数为num+1;
2、count>num,则进行num+1,count -= num;之后再进行判断,因为每一个num对应的人数最多为num+1,所以要减去num重新判断。

即比如2 2 2 2;这四个2是不同阵容的,num+1,count -= num,即前三个2位一组颜色(2组成的最大人数),后一个另一组颜色。人数也为:(2+1)+(2+1)。

由于题目对输入的限制,所以我们可以直接用数组来完成即可。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20




#include <iostream>
#include <map>
#include <algorithm>

using namespace std;

int main()
{
    map<int, int>mp;
    int num;
    while(cin>>num) {
        if(mp.find(num) == mp.end()) {//没有则建立字典
            mp.insert(make_pair(num, 1));
        }
        else
            mp.find(num)->second += 1;
    }
    int res = 0;
    for(map<int,int>::iterator i=mp.begin(); i!=mp.end(); ) {
        if(i->first == 0) {//均不同则键对应的值就是人数
            res += i->second;
            ++i;
        }
        else {
            res += i->first+1;
            if(i->second <= i->first+1) ++i;
            else i->second -= (i->first + 1);
        }
    }
    cout<< res << endl;
}
数组版:
#include <iostream>

using namespace std;

int main()
{
    int mp[1001] = {0};
    int num;
    //先统计输入有几个不同的值。
    while(cin>>num) {
        mp[num]++;
    }
    
    int res = mp[0];
    for(auto i=1; i<1001; ) {
        if(mp[i] != 0) {//寻找出现的值
            res += i+1;
            if(mp[i] <= i+1) ++i;
            else mp[i] -= (i+1);
        } else
            ++i;
    }
    cout<< res << endl;
}


编辑于 2019-09-08 18:40:41 回复(5)
//这道题非常适合使用map进行解答
#include<iostream>
#include<map>
//#include<algorithm>
 
using namespace std;
int main()
{
    map<int,int> child;
    int aa,num=0;
 
    while(cin>>aa)
    {
        if(child.find(aa)==child.end())
        {
            child[aa] = 1;
        }
        else
        {
            ++child[aa];
        }
    }
 
    int key,nv;
    for(map<int,int>::iterator iter(child.begin());iter!=child.end();++iter)
    {
        key=iter->first;
        nv=iter->second;
        num += (nv/(key+1))*(key+1) + ((nv%(key+1)==0)?0:(key+1));
 
    }
    cout<<num;
 
    return 0;
}

发表于 2019-08-07 22:27:32 回复(0)