HDU 3591 The trouble of Xiaoqian

The trouble of Xiaoqian

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 2465    Accepted Submission(s): 871


Problem Description
In the country of ALPC , Xiaoqian is a very famous mathematician. She is immersed in calculate, and she want to use the minimum number of coins in every shopping. (The numbers of the shopping include the coins she gave the store and the store backed to her.)
And now , Xiaoqian wants to buy T (1 ≤ T ≤ 10,000) cents of supplies. The currency system has N (1 ≤ N ≤ 100) different coins, with values V1, V2, ..., VN (1 ≤ Vi ≤ 120). Xiaoqian is carrying C1 coins of value V1, C2 coins of value V2, ...., and CN coins of value VN (0 ≤ Ci ≤ 10,000). The shopkeeper has an unlimited supply of all the coins, and always makes change in the most efficient manner .But Xiaoqian is a low-pitched girl , she wouldn’t like giving out more than 20000 once.
 
Input
There are several test cases in the input.
Line 1: Two space-separated integers: N and T.
Line 2: N space-separated integers, respectively V1, V2, ..., VN coins (V1, ...VN)
Line 3: N space-separated integers, respectively C1, C2, ..., CN
The end of the input is a double 0.
 
Output
Output one line for each test case like this ”Case X: Y” : X presents the Xth test case and Y presents the minimum number of coins . If it is impossible to pay and receive exact change, output -1.
 
Sample Input
3 70 5 25 50 5 2 1 0 0
 
Sample Output
Case 1: 3
 
题意就是小钱要去买价值为T的商品,怎样付钱,能给店员的硬币数+店员找给他的硬币数最少。
给钱用多重背包,且是恰好装满的情况,找钱用完全背包,也要是恰好装满的情况。
 
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
using namespace std;
int main()
{
    int k,n,t;
    int dp1[20001];//用背包保存需要货币的数量
    int dp2[20001];
    int v[105];
    int c[105];
    int cou[15000];
    int val[15000];
    k = 1;
    while (cin >> n >> t)
    {
        int INF = 99999999;
        int imin = INF;
        if (n == 0 && t == 0) break;
        int i, j;
        for (i = 1; i <= 20000; i++)//因为要恰好凑成,初始化为无穷
            dp1[i] = dp2[i] = INF;
        dp1[0] = dp2[0] = 0;//0的时候为0时恰好装满
        for (i = 1; i <= n; i++)
        {
            cin >> v[i];
        }
        for (i = 1; i <= n; i++)
        {
            cin >> c[i];
        }
        int count = 1;
        int u;
        for (i = 1; i <= n; i++)
        {
            for (u = 1; u <= c[i]; u <<= 1)//二进制优化
            {
                val[count] = u*v[i];//比如13个5块,被分为价值为1*5,2*5,4*5,6*5的各一个
                cou[count++] = u;//用来存放打包成一起的价值里有多少硬币,比如上面拆分13中,10面值的包含2个硬币
                c[i] -= u;
            }
            if (c[i] > 0)
            {
                val[count] = c[i]*v[i];
                cou[count++] = c[i];
            }
        }
        for (i = count - 1; i>=1; i--)//给钱多重背包
        {
            for (j = 20000; j >= val[i]; j--)
            {//dp1[j]表示凑成j的价值需要的最少的硬币
                dp1[j] = min(dp1[j], dp1[j - val[i]] + cou[i]);
            }
        }
        for (i = 1; i <= n; i++)//找钱完全背包
        {
            for (j = v[i]; j <= 20000; j++)
            {
                dp2[j] = min(dp2[j - v[i]] + 1, dp2[j]);
            }
        }
        for (i = t; i <= 20000; i++)
        {
            if (dp1[i] + dp2[i - t] < imin)
                imin = dp1[i] + dp2[i - t];
        }
        if (imin < INF)
            printf("Case %d: %d
", k, imin);
        else
            printf("Case %d: -1
", k);
        k++;
    }
    return 0;
}
原文地址:https://www.cnblogs.com/caiyishuai/p/13271307.html