罐子与硬币--【英雄会】

这篇博客讨论了一道名为'罐子与硬币'的英雄会题目,涉及在不知道罐子内容的情况下,如何通过有限次机会获取至少c枚硬币。博主分析了错误的策略,如均匀分配硬币,以及思考过程,最终提出一个解决方案:使用n1个空罐,n2个含k1硬币的罐,n3个含k2硬币的罐(k1<k2)。通过这种方式,找到了在罐子被打乱后能确保获取c硬币所需的最小次数p。
摘要由CSDN通过智能技术生成

好久没来英雄会了,所以今天来看看几题,看到“罐子与硬币”这一题不错,这种题目比较适合我的味道,不过,可惜啊...性子太急,分没到手...

题目如下:

有n个罐子,有k个硬币,每个罐子可以容纳任意数量的硬币。罐子是不透明的,起初你可以随机把这k个硬币任意放在罐子里。然后罐子被打乱顺序,你从外表无法区别罐子。最后罐子被编上号1-n。你有p次机会,每次你可以选择某个罐子,如果该罐子里有硬币,则你可以得到1个(你不可以知道该罐子里有多少硬币),如果该罐子是空的,你得不到任何硬币。

你最终要得到至少c枚硬币,我们的问题是给定n,k,c,求出最少的p,存在一种你最初放硬币的方式,无论罐子如何被打乱顺序,你都能p次机会内获得至少c个硬币。 

输入n,k,c (0 < n <=1000000, 0 < c <= k <=1000000)。

输出,最小的p值。 例如n = 3, k = 6, c = 4。 你可以把每个罐子放入两个硬币,这样得到4次机会可以得到4个硬币,输出4。

题目的要求是:无论罐子如何被打乱顺序,都能p次机会内获得至少c个硬币。我们可以这样理解,只要存在空的,我们肯定会选中;

错误1:将k个硬币先均匀分到n个罐子中,多余的部分则每一个分到罐子中;

这样提交:

    if(k < c)
       return 0;
    int num = k / n;  //每个罐子可以放的硬币
    int count  = k % n;  //多出的硬币
    if(num * n >= c)
        return c;
    else
    {
        int count1 = n - count;  //此时的空瓶
        int p = count1 + c;
        return p;
    }
测试点n = 3, k = 6, c = 4倒是过了,可是提交上去,说测试点n = 3, k = 4,c = 4没过;

运行了一下,我的结果是6

可是一想,如第一个罐子为空,第二个,第三个罐子放两个

这样我们首先抽到第一个罐子,后面四次分别为第二个、第三个、第二个、第三个,只需五次即可

错误2:所以这样理解,将k个硬币真正均分至i个罐子中,n - i个罐子为空,如下:

    if(k < c)
        return 0;
    int num = k / n;  //每个罐子可以放的硬币
    if(num * n >= c)
        return c;
    else
    {
        for(int i = n; i > 0; i--)
        {
            if(k % i == 0)
            {
                return c + n - i;
            }
        }
    }

可是这样的结果依然没过,测试点n = 1000, k = 12345, c = 12340,我的结果是12517。

这次的数据有点大,我也画不出来啊...

终结:这时候想到早上转的篇文章,当你学不进去的时候,试试“普瑞馬”法则中的大脑集中精力最多只有25分钟。这是对成人而言,所以学习20到30分钟后就应该休息10分钟。你可以利用这段时间做点家务,10分钟后再回来继续学习,效果会更好。”正巧到饭点的时间,就去吃了个饭,回来突发奇想:

我们可以有n1个罐子是空的,n2个罐子是装k1个硬币的(n2为1或0),n3个罐子是装k2个硬币的。

n1 + n2 + n3 = n;

n1 * 0 + n2 * k1 + n3 * k2 = k;

其中包括的上面的第二种情况,即n2 = 0时,有n1 + n2个罐子为空,n3个罐子是k2个硬币,当然k1 < k2,否则我们寻找硬币到后来连n3个空罐子都得加上了...;

#include <stdio.h>
#include <iostream>
#include <string>
using namespace std;
class Test {
public:
    static int pvalue (int   n,int   k,int   c)
    {
    if(k < c)
        return 0;
    int num = k / n;  //每个罐子可以放的硬币
    int max = 100000000;
    if(num * n >= c)
        return c;
    else
    {
        for(int i = n - 1; i > 0; i--)
        {
            num = k / i;  //装i个整罐子,每个装num
            int num1 = k - num * i;  //多的一个罐子装num1个
            int p;
            if(num1 == 0)  //
            {
                p = n - i + c;
            }
            else
            {
                if(c <= num1 * (i + 1) && num > num1)
                {
                    p = n - i - 1 + c;
                }
                else if(num > num1)
                    p = n - i - 1 + c + 1;
                else
                    p = c + n - 1;
            }
            if(max > p)
                max = p;
        }
    }
    return max;
    }
};
//start 提示:自动阅卷起始唯一标识,请勿删除或增加。
int main()
{   
    cout<<Test::pvalue(3,4,4)<<endl;   
} 
//end //提示:自动阅卷结束唯一标识,请勿删除或增加。  


老话说,事不过三,这第三次的提交终于对了...

(*∩_∩*)


评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值