POJ--1787--Charlie's Change--揹包變形

Charlie's Change
Time Limit: 1000MS   Memory Limit: 30000K
Total Submissions: 3154   Accepted: 907

Description

Charlie is a driver of Advanced Cargo Movement, Ltd. Charlie drives a lot and so he often buys coffee at coffee vending machines at motorests. Charlie hates change. That is basically the setup of your next task. 

Your program will be given numbers and types of coins Charlie has and the coffee price. The coffee vending machines accept coins of values 1, 5, 10, and 25 cents. The program should output which coins Charlie has to use paying the coffee so that he uses as many coins as possible. Because Charlie really does not want any change back he wants to pay the price exactly. 

Input

Each line of the input contains five integer numbers separated by a single space describing one situation to solve. The first integer on the line P, 1 <= P <= 10 000, is the coffee price in cents. Next four integers, C1, C2, C3, C4, 0 <= Ci <= 10 000, are the numbers of cents, nickels (5 cents), dimes (10 cents), and quarters (25 cents) in Charlie's valet. The last line of the input contains five zeros and no output should be generated for it.

Output

For each situation, your program should output one line containing the string "Throw in T1 cents, T2 nickels, T3 dimes, and T4 quarters.", where T1, T2, T3, T4 are the numbers of coins of appropriate values Charlie should use to pay the coffee while using as many coins as possible. In the case Charlie does not possess enough change to pay the price of the coffee exactly, your program should output "Charlie cannot buy coffee.".

Sample Input

12 5 3 1 2
16 0 0 0 1
0 0 0 0 0

Sample Output

Throw in 2 cents, 2 nickels, 0 dimes, and 0 quarters.
Charlie cannot buy coffee.

題意:告訴你1、5、10、25單位金幣的數量和一個金幣值n,求所有用這些金幣組成這個n的方案中使用金幣最多的那個,分別輸出每種硬幣使用的數量

昨天我可是瞅了大半天都沒瞅出啥把戲出來啊,寫了好幾次,都是半路中間讓我糾結,所以去溜別個的博客採陰補陽去了,看到一個寫法跟我一樣,但是犀利了很多,比如最後查詢,巧妙的採用了 i 與 i-1 之間的差值,哎,是我太笨

解析:多重揹包,把金額作爲容量,也就是dp的下標,dp[x]中裝的是組成金額爲 x 的使用金幣數量的最大值,然後我用dis記錄前驅點,比如dp[x]=dp[x-v]+m,則dis[x]=x-v,

然後重要的是每次作用的金幣要在對應的dp[ ]數組中記錄這個點所在路徑上使用的數量


#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int main (void)
{
    int n,m,i,j,k,l,num[4],val[4]={1,5,10,25};
    int dp[11111],dis[11111],v[11111];
    int x[33];
    while(~scanf("%d",&n))
    {
        if(n==0)k=1;
        else k=0;
        for(i=0;i<4;i++)
        {
            scanf("%d",&num[i]);
            if(num[i])k=0;
        }
        if(k)break;
        memset(dp,-1,sizeof(dp));
        dp[0]=0;
        memset(dis,0,sizeof(dis));
        dis[0]=-1;
        for(i=0;i<4;i++)
        {
            memset(v,0,sizeof(v));
            for(j=val[i];j<=n;j++)
            if(dp[j-val[i]]>=0&&v[j-val[i]]<num[i]&&dp[j]<dp[j-val[i]]+1)
            {
                dp[j]=dp[j-val[i]]+1;	//使用金幣數量最大值
                dis[j]=j-val[i];	//記錄前驅點,前驅點的金額加上這次裝入的金幣金額等於這次的金額
                v[j]=v[j-val[i]]+1;	//記錄 i 號金幣已經在這條路徑上使用的數量
            }
        }
        if(dp[n]>0)
        {
            memset(x,0,sizeof(x));
            i=n;
            while(dis[i]>=0)
            {
                x[i-dis[i]]++;	//dis中:a+金幣金額=b,所以金幣金額=b-a
                i=dis[i];	//直接往記錄的前驅點跳躍
            }
            printf("Throw in %d cents, %d nickels, %d dimes, and %d quarters.\n",x[val[0]],x[val[1]],x[val[2]],x[val[3]]);
        }else
        {
            puts("Charlie cannot buy coffee.");
        }
    }
    return 0;
}

總結:我就記得01揹包跟完全揹包,然後腦子裏面還有一個多重揹包,我記得是數量從1到K一個一個去01揹包的,這個方法很耗時,然後是有個二進制壓縮的方法,使用2的0次方到n次方來進行完全揹包,這個是一般多重揹包通用的方案,這次不會寫多重了,畢竟很久沒動了,所以看了自己以前寫的,結果。。尼瑪,看懂了,卻發現這個題在使用的時候要考慮情況,就是沒有方案的時候不能疊加,哎,以後這做題不能停的,停一天可就要當一年的傻逼了


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章