每日一题之零钱兑换--完全背包问题

 情景引入:虽然随着时代发展,现在我们都用支付宝,微信等进行支付,但我相信大家都有过用现金付钱的时候,当时你是否思考如何快速找出最优方法(我们假设你每种货币类型都有无限个)(你是亿万富豪),其实这是一个编程问题--如何用最轻的货币质量来支付呢

概念介绍:有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

注意:开辟要多开一个空间,防止栈溢出!

关注我,下期,我将讲解循环队列

  • 30
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值