1. 程式人生 > >Piggy-Bank(最小完全揹包問題)

Piggy-Bank(最小完全揹包問題)

Piggy-Bank

Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 65536/32768K (Java/Other)
Total Submission(s) : 14   Accepted Submission(s) : 6

Font: Times New Roman | Verdana | Georgia

Font Size: ← →

Problem Description

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!

Input

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.

Output

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.".

Sample Input

3
10 110
2
1 1
30 50
10 110
2
1 1
50 30
1 6
2
10 3
20 4

Sample Output

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.

Source

Central Europe 1999  題目大意: 就是給定銀行的最大重量,以及給出每個人的錢數及重量,求能恰好裝滿銀行的最小錢數,如果不能恰好裝滿,則輸出不可能 求最小值我參考的揹包九講,下面就是擷取的揹包九講的內容:

初始化的細節問題

我們看到的求最優解的揹包問題題目中,

事實上有兩種不太相同的問法。

有的題

目要求“恰好裝滿揹包”時的最優解,有的題目則並沒有要求必須把揹包裝滿。

一種區別這兩種問法的實現方法是在初始化的時候有所不同。

如果是第一種問法,要求恰好裝滿揹包,那麼在初始化時除了

f[0]

0

其它

f[1..V]

均設為

-

∞,這樣就可以保證最終得到的

f[N]

是一種恰好裝滿揹包的最

優解。

如果並沒有要求必須把揹包裝滿,而是隻希望價格儘量大,初始化時應該將

f[0..V]

全部設為

0

為什麼呢?可以這樣理解:

初始化的

f

陣列事實上就是在沒有任何物品可以放入

揹包時的合法狀態。

如果要求揹包恰好裝滿,

那麼此時只有容量為

0

的揹包可能

被價值為

0

nothing“恰好裝滿”,其它容量的揹包均沒有合法的解,屬於未

定義的狀態,它們的值就都應該是

-

∞了。如果揹包並非必須被裝滿,那麼任何

容量的揹包都有一個合法解“什麼都不裝”,這個解的價值為

0

,所以初始時狀

態的值也就全部為

0

了。

初始化的細節問題

我們看到的求最優解的揹包問題題目中,事實上有兩種不太相同的問法。有的題目要求“恰好裝滿揹包”時的最優解,有的題目則並沒有要求必須把揹包裝滿。一種區別這兩種問法的實現方法是在初始化的時候有所不同。

如果是第一種問法,要求恰好裝滿揹包,那麼在初始化時除了f[0]為0其它f[1..V]均設為-∞,這樣就可以保證最終得到的f[N]是一種恰好裝滿揹包的最優解。

如果並沒有要求必須把揹包裝滿,而是隻希望價格儘量大,初始化時應該將f[0..V]全部設為0。

為什麼呢?可以這樣理解:初始化的f陣列事實上就是在沒有任何物品可以放入揹包時的合法狀態。如果要求揹包恰好裝滿,那麼此時只有容量為0的揹包可能被價值為0的nothing“恰好裝滿”,其它容量的揹包均沒有合法的解,屬於未定義的狀態,它們的值就都應該是-∞了。如果揹包並非必須被裝滿,那麼任何容量的揹包都有一個合法解“什麼都不裝”,這個解的價值為0,所以初始時狀態的值也就全部為0了。

這個小技巧完全可以推廣到其它型別的揹包問題,後面也就不再對進行狀態轉移之前的初始化進行講解。

程式碼實現:
#include<stdio.h>
#define MAX 2000000000//代表無窮大(注意,足夠大就好,不要太大,以免出現溢位的危險導致結果混亂)
#define N 10000
int p[N],dp[N],v[N];
void set(int dp[],int V)//賦初值
{
    int i;
    dp[0]=0;
    for(i=1;i<=V;i++)
    {
        dp[i]=MAX;
    }
}
int main()
{
    int t,V,v1,v2,n,i,j;
    while(~scanf("%d",&t))
    {
        while(t--)
        {
            scanf("%d%d",&v1,&v2);
            V=v2-v1;
            scanf("%d",&n);
            for(i=0;i<n;i++)
            {
                scanf("%d%d",&p[i],&v[i]);
            }
            set(dp,V);
            for(i=0;i<n;i++)
            {
                for(j=v[i];j<=V;j++)
                {
                        dp[j]=dp[j]<dp[j-v[i]]+p[i]?dp[j]:dp[j-v[i]]+p[i];
                }
            }
            if(dp[V]!=MAX)//判斷是否恰好裝滿
                printf("The minimum amount of money in the piggy-bank is %d.\n",dp[V]);
            else
                printf("This is impossible.\n");
        }
    }
    return 0;
}