對於揹包問題在前面動態規劃 - 0-1揹包問題的算法優化已經講到了關於0-1揹包問題的解法,0-1揹包問題是最基本的揹包問題,它的特色是:每一件物品之多隻能選擇一件,即在揹包中該物品數量只有0和1兩種狀況。php
如今擴展一下,有一個容積爲V的揹包,同時有n種物品,每種物品均有無數多個,而且每種物品的都有本身的體積和價值。求使用該揹包最多可以裝的物品價值總和。html
這就是徹底揹包問題。算法
若是按照0-1揹包的思路求解該問題,可設當前物品的體積爲w,價值爲v,考慮到揹包中最多存放V/w件該物品,那麼該物品的可選數量就爲V/w件。依次能夠對全部的物品進行拆分,最後對拆分的全部物品作0-1揹包便可獲得答案。可是,這樣拆分會使物品數量大大增長,其時間複雜度爲:O(V*∑ni=1(V/wi))。ide
可見,當V較大時每一個物品的體積較小時,其時間複雜度會顯著增大。因此將徹底揹包問題轉化爲0-1揹包問題去解決的方法不可靠。post
在0-1揹包的解決算法中,其中一段代碼是該算法的核心算法,以下:優化
struct Good{ int w; int v; }goods[101]; int dp[101][1001]; int n,S;//n表示有n個物品,S表示揹包的最大容積 for (i = 1; i <= n; i++) { for (j = S; j >= goods[i].w; j--) dp[j] = max(dp[j], dp[j - goods[i].w] + goods[i].v); }
在這段代碼中,之所將j初始化爲S,逆序循環更新狀態是爲了保證在更新dp[j]時,dp[j-goods[i].w]的狀態還沒有由於本次更新而發生改變,即等價於由this
dp[i-1][j-goods[i].w]轉移獲得dp[i][j]。保證了更新dp[j]時,dp[j-goods[i].w]是沒有放入物品i時的數據dp[i-1][j-goods[i].w]。編碼
在解決徹底揹包問題時,能夠借鑑這個思路。在徹底揹包中,每一個物品能夠被無限次選擇,那麼狀態dp[i][j]剛好能夠由可能已經放入物品i的狀態dp[i][j-goods[i].w]轉移而來。能夠將上面的代碼改寫以下:url
for (i = 1; i <= n; i++) { for (j = goods[i].w; j <= S; j++) dp[j] = max(dp[j], dp[j - goods[i].w] + goods[i].v); }
九度教程102題:Piggy-Bankidea
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 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.".
編碼實現:
#include <stdio.h> #define INF (1e8) int dp1[10001]; int v[501], w[501]; int min(int a, int b) { return a < b ? a : b; } int main() { int Ncase; scanf("%d", &Ncase); while (Ncase--) { int wEmptyPig, wFullPig; scanf("%d%d", &wEmptyPig, &wFullPig); int wMoney = wFullPig - wEmptyPig; int countOfMoneySp; scanf("%d", &countOfMoneySp); for (int i = 1; i <= countOfMoneySp; i++) { scanf("%d%d", &v[i], &w[i]); } for (int i = 0; i <= wMoney; i++) dp1[i] = INF; dp1[0] = 0; for (int i = 1; i <= countOfMoneySp; i++) { for (int j = w[i]; j <= wMoney; j++) { if (dp1[j - w[i]] != INF) dp1[j] = min(dp1[j], dp1[j - w[i]] + v[i]); } } if (dp1[wMoney] == INF) printf("This is impossible.\n"); else printf("The minimum amount of money in the piggy-bank is %d.\n", dp1[wMoney]); } return 0; } /************************************************************** Problem: 1454 User: 凌月明心 Language: C++ Result: Accepted Time:70 ms Memory:1064 kb ****************************************************************/
徹底揹包問題,其特色爲每種物品可選的數量爲無數個,其解法與0-1揹包總體保持一致,不一樣點在於狀態更新時的遍歷順序。