POJ-1384 Piggy bank 完全背包问题

来源:互联网 发布:古龙顺序知乎 编辑:程序博客网 时间:2024/04/29 20:39

这是算法课的一次作业,是完全背包问题。


描述
Before ACM can do anything, a budget must be prepared and the necessary financial support obtained. The main income for this action comes from Irreversibly Bound Money (IBM). The idea behind is simple. Whenever some ACM member has any small money, he takes all the coins and throws them into a piggy-bank. You know that this process is irreversible, the coins cannot be removed without breaking the pig. After a sufficiently long time, there should be enough cash in the piggy-bank to pay everything that needs to be paid.

But there is a big problem with piggy-banks. It is not possible to determine how much money is inside. So we might break the pig into pieces only to find out that there is not enough money. Clearly, we want to avoid this unpleasant situation. The only possibility is to weigh the piggy-bank and try to guess how many coins are inside. Assume that we are able to determine the weight of the pig exactly and that we know the weights of all coins of a given currency. Then there is some minimum amount of money in the piggy-bank that we can guarantee. Your task is to find out this worst case and determine the minimum amount of cash inside the piggy-bank. We need your help. No more prematurely broken pigs!
输入
The input consists of T test cases. The number of them (T) is given on the first line of the input file. Each test case begins with a line containing two integers E and F. They indicate the weight of an empty pig and of the pig filled with coins. Both weights are given in grams. No pig will weigh more than 10 kg, that means 1 <= E <= F <= 10000. On the second line of each test case, there is an integer number N (1 <= N <= 500) that gives the number of various coins used in the given currency. Following this are exactly N lines, each specifying one coin type. These lines contain two integers each, Pand W (1 <= P <= 50000, 1 <= W <=10000). P is the value of the coin in monetary units, W is it’s weight in grams.
输出
Print exactly one line of output for each test case. The line must contain the sentence “The minimum amount of money in the piggy-bank is X.” where X is the minimum amount of money that can be achieved using coins with the given total weight. If the weight cannot be reached exactly, print a line “This is impossible.”.
样例输入
3
10 110
2
1 1
30 50
10 110
2
1 1
50 30
1 6
2
10 3
20 4
样例输出
The minimum amount of money in the piggy-bank is 60.
The minimum amount of money in the piggy-bank is 100.
This is impossible.


大致含义是:给一个钱的总质量W,和N种钱币的币值和质量,求得一个满足重量W的价值最小结果,如果无法实现总重量为W,则输出“impossible”。因为没有算法基础,这个题一开始看的时候是一脸蒙蔽的。本来想用贪心做,具体思路是先求每种钱币的价值/质量比值,比值越小的优先度越高,一个一个放。最后思来想去不知道如何能实现正好放满一个背包的算法,由于无法解决“如何放物品能够恰好放满背包”的问题,这种思路被放弃了。
接下来是完全背包解法:首先给定一个数组dp[W]={9999999};含义就是在包内重量为w的时候,包中价值为dp[w]。然后我们把所有的放法都遍历一遍,然后更小的值覆盖dp[w],这样就能得到dp[W]的最小值。思路精妙之处在于:如果没有一种方法能够达到W,则dp[W]的值就不会改变,所以最后判断dp[W]是否为9999999就可以判断是否possible了。 遍历的方式为,从第一个币种开始装,装到装不下为止,这个时候会更新对应重量的dp值。接下来在这个基础上装第二个币种,如果能够使得dp更小则就改变装法,把之前的换下来,不过我们并不关心怎么换的,只需要把这个重量下的当前最小装载价值记录在dp中即可,因为之后的每一步决策都是在这个局部最优的基础上进行的。 最终所有币种考虑完毕,也就找到了最小的价值。不过,这个方法的缺点是不能通过回溯来得到具体装配方式。

# include <iostream>#include <vector>using namespace std;int p[505];int w[505];int main(){    int T;    cin >> T;    while (T--){        vector <int> dp(50005, 999999);        int E, F;        cin >> E >> F;        int N;        cin >> N;        for (int i = 0; i < N; i++){            cin >> p[i] >> w[i];        }        int W = F - E;        dp[0] = 0;        for (int i = 0; i < N; i++){            for (int j = w[i]; j <= W; j++){                int u = dp[j - w[i]] + p[i];                dp[j] = u < dp[j] ? u : dp[j];            }        }        if (dp[W] == 999999){            cout << "This is impossible." << endl;;        }        else{            cout << "The minimum amount of money in the piggy-bank is " << dp[W] << "."<<endl;        }    }    return 0;}
0 0
原创粉丝点击