笔试强训day29(最小组成和+猜硬币)

目录

第一题-最小组成和

第二题-猜硬币


第一题-最小组成和

思路:

  • 如果没有把第i个物品放在背包:很显然,既然没有把第i个放进去,那么价值量不会增加,状态也不会变化,也即dp[i][w]==dp[i-1][w]
  • 如果把第i个物品放入了背包:既然放入了背包,那么此状态的容量一定会减少wt[i],而价值则会增加val[i],因此dp[i][w]==dp[i-1][w-wt[i-1]]+val[i-1]

需要注意的是i是从1开始的,因此valwt的索引中i-1表示第i个物品。所以dp[i][w]==dp[i-1][w-wt[i-1]]+val[i-1]表示如果把第i个物品装入了,就要寻找剩余重量w-wt[i-1]限制下的最大价值,加上第i个物品的价值val[i-1]

class Solution {
public:
	/**
	 *	正数数组中的最小不可组成和
	 *	输入:正数数组arr
	 *	返回:正数数组中的最小不可组成和
	 */
	int getFirstUnFormedNum(vector<int> arr, int len) {
        int max = 0;
        int min = arr[0];
        //找到max和min
        for(int i = 0 ; i < len; ++i)
        {
            if(min>arr[i])
                min = arr[i];
            max+=arr[i];
        }
        vector<int>dp(max+1, 0);
        for(int i = 0; i < len; ++i)
        {
            //j表示背包空间大小
            //dp[j]表示背包最大承重
            for(int j = max; j >= arr[i]; --j)
            {
                //如果当前背包空间减去要放入空间大小的最大容量,再放入这个物品
                if(dp[j] < dp[j-arr[i]]+arr[i])
                {
                    dp[j] = dp[j-arr[i]]+arr[i];
                }
            }
        }
        //最后只要放入的重量不是那个区间的数肯定就是所求
        for(int i = min; i <= max;++i)
        {
            if(i!=dp[i])
                return i;
        }
        return max+1;
    }
};

第二题-猜硬币

思路:

        

当n = 1时,不需要再称了,它就是假币,总共需要0次
当n = 2时,1、1放天平两端,轻的就是假币,总共需要1次
当n = 3时,随机抽出2个放到天平两端,如果天平平衡,则剩下1个就是假币,
    否则天平中较轻的是假币,总共需要1次
当n = 4时,分成1、1、2,天平秤1、1,注意题目要求最短时间,
    并且是次数最大的情况,也就是我们需要考虑最坏的情况,第一次1、1重量相等,
    接着我们把2分开称,总共需要2次
当n = 5时,分成2、2、1,天平秤2、2,同样考虑最坏的情况,2、2重量相等,
    接着我们把2分开称,总共需要2次
当n = 6时,分成2、2、2,天平秤2、2,同样考虑最坏的情况,不管如何,还需要
    把2分开称,总共需要2次
当n = 7时,分成2、2、3,天平先称2、2,考虑最坏的情况,重量相等,接着我们就需要
    按照n = 3的最优情况称,总共需要2次
...

其中有一个规则,我们每次把n分成是3堆,
    如果n % 3 == 0,分成 n/3、 n/3、 n/3三堆, 剩下 n/3
    如果n % 3 == 1,分成 n/3、 n/3、1 + (n/3)三堆,最坏剩下 1 + (n/3)
    如果n % 3 == 2,分成 n/3、 1 + (n/3)、1 + (n/3)三堆,最坏剩下 1 + (n/3)
 

#include<iostream>
using namespace std;
int main ()
{
    int n;//硬币数量
    while(cin>>n)
    {
        if(n == 0)
            return 0;
        int count = 0;
        while(n>1)
        {
            count++;
            //每次取1/3,如果不能整除3,有两种情况
            //剩余1个,分成 1/3 、1/3 、1 + (1/3) ,两个1/3放入天平两端,
            //剩余2个,分成 1/3 、1 + (1/3) 、 1 + (1/3),两个1 + (1/3)放入天平两端
            //由于题目要求最快的时间,并且是求最多的次数,因此取每次剩余的最大值 1 + (1/3)
            n = n/3+(n%3>0);
        }
        cout<<count<<endl;
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

penguin_bark

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

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

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

打赏作者

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

抵扣说明:

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

余额充值