目录
第一题-最小组成和
思路:
- 如果没有把第
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开始的,因此val
和wt
的索引中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;
}