情景引入:虽然随着时代发展,现在我们都用支付宝,微信等进行支付,但我相信大家都有过用现金付钱的时候,当时你是否思考如何快速找出最优方法(我们假设你每种货币类型都有无限个)(你是亿万富豪),其实这是一个编程问题--如何用最轻的货币质量来支付呢!
概念介绍:有N种物品和一个容量为V的背包,每种物品都有无限件可用。第i种物品的体积是c,价值是w。将哪些物品装入背包可使这些物品的体积总和不超过背包容量,且价值总和最大。
基本思路:
1,可以用数据顺序表(定义数组指针,空间不够扩容等)暴力进行列举(不推荐)
2,我们可以参照01背包问题!写二维数组定义dp[i][v],表示前i种物品恰放入一个容量为v的背包的最大权值。按照每种物品不同的策略写出状态转移方程,但是,这跟01背包问题一样有O(N*V)个状态需要求解。(容易想到)
对于二,我曾经对于01背包问题方法题画了一张图,虽然不是我们本章讨论的问题,但我希望您能多一些理解这种方法!
3,完全背包问题有一个很简单有效的优化,是这样的:若两件物品i、j满足c<=c[j]且w>=w[j],则将物品j去掉,不用考虑。这个优化的正确性显然:任何情况下都可将价值小体积高的j换成物美价廉的i,得到至少不会更差的方案。对于随机生成的数据,这个方法往往会大大减少物品的件数,从而加快速度。然而这个并不能改善最坏情况的复杂度,因为有可能特别设计的数据可以一件物品也去不掉(第三种为官方最优解!)
分析情景并进行解决:
1, 我们假设我们货币有以下几种类型:1元,5元,10元,20元,50元,100元(即物品的价值);
2,为了方便理解,我们假设我们要支付的钱为100,200,300,400,500元(即背包的承重),我们先升序排序
注意是局部优解!
画出二维表格dp!如下:
我们单独用weight存重量,value存价值
3,思路核心为:我们从0开始,看货币从1块开始能否是我们要支付的数额,我们先当当前货币不存在,继承上一层的状态即dp[i][j]=dp[i-1][j]; 如果能装下(dp[i][j]-weighti[i]>=0),就考虑装再装进当前类型的数额 else(dp[i][j]=max(dp[i][j],dp[i][j-weight[j])+value[i]);
注意:我们要在其剩余价值中,包括当前的货币类型的值!
简单代码区:
我们不难画出如下:(保密)(画好的铁汁们关注我,我定时发)
真题演练:
转载:题解:
int temp(void* a1,void*a2)
{
return *(int*)a1 - *(int*)a2; //升序
}
int min(int a,int b) {return a<=b?a:b;}
int coinChange(int* coins, int coinsSize, int amount){
qsort(coins,coinsSize,sizeof(int),temp);
int* dp=malloc(sizeof(int)*(amount+1));
for(int i=1;i<=amount;i++)
{
dp[i]=INT_MAX;
}
dp[0]=0;
for(int i=0;i<coinsSize;i++)
{
for(int j=coins[i];j<=amount;j++)
{
if(dp[j-coins[i]]!=INT_MAX)
{
dp[j]=min(dp[j-coins[i]]+1,dp[j]);
}
}
}
if(dp[amount]==INT_MAX) return -1;
return dp[amount];
}
此处引进一个作者的答案:Sunflower
注意:开辟要多开一个空间,防止栈溢出!
关注我,下期,我将讲解循环队列