1. 程式人生 > >Optimal Coin Change(揹包)

Optimal Coin Change(揹包)

題目大意:

      給你一筆錢,你有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;
}