ACM 2017 香港区域赛 G - Optimal Coin Change(背包)

10 篇文章 0 订阅
2 篇文章 0 订阅

https://nanti.jisuanke.com/t/19931

(uva数据有问题,计蒜客可以交)

题目大意:

      给你一笔钱,你有n个面值的硬币,问兑换这笔钱用多少个硬币,让硬币数量最少(若有多组答案,输出尽可能使用面额小的钱币)

题解:

     完全背包+路径输出

     dp[i]代表兑换面值为i的钱需要的最少硬币数量

     对于第i个硬币,用还是不用(完全背包的思想)

            dp[j+a[i]]=min(dp[j+a[i]],dp[j]+1)

      然后因为要记录第几个硬币用几个,所以再开一个数组c[i][j]表示兑换面值为i的钱,第j个硬币用了几个

 

      注意可能有些人会觉得题目要求让硬币数量最少,但是输出的时候又有一个要求是如果有多个解,输出尽可能使用面值小的硬币的方案,什么意思呢

就像第三个样例

43 5 1 2 21 40 80

答案是1 1 0 1 0

但我还可以 1 0 2 0 0

     但这样显然1 1 0 1 0这组方案使用了更小的面值小的硬币,所以答案是它

     这种选择就体现在if(dp[j+a[i]]>=dp[j]+1) 这个等于号上,如果使用了更多面值小的硬币,那么剩余的金额一定更大,所以一定后更新到

#include<bits/stdc++.h>
#include<cstring>
#define ll long long
using namespace std;
#define INF 0x3f3f3f3f
int a[20];
int dp[2010];
int c[2010][20];
int main()
{
    //freopen("input.txt","r",stdin);
    int n,v;
    while(~scanf("%d%d",&v,&n))
    {
        for(int i=1;i<=n;++i)
            scanf("%d",&a[i]);
        memset(dp,INF,sizeof(dp));
        memset(c,0,sizeof(c));
        dp[0]=0;
        for(int i=1;i<=n;++i)
            for(int j=0;j<=v;++j)
            if(j+a[i]<=v)
            {
                if(dp[j+a[i]]>=dp[j]+1)
                {
                    dp[j+a[i]]=dp[j]+1;
                   for(int k=1;k<=n;++k)
                   {
                       c[j+a[i]][k]=c[j][k];
                   }
                   c[j+a[i]][i]++;
                }
            }
        if(dp[v]==INF)
            puts("-1");
        else
        {
            for(int i=1;i<n;++i)
               printf("%d ",c[v][i]);
            printf("%d\n",c[v][n]);
        }
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值