這道題是一道完全揹包練手很好的題,比較容易,但是與純的完全揹包相比卻做了部分很巧的改動。其一,這是一個要求裝滿的完全揹包。其二,這個揹包求得並不是最大值,而是最小值。那麼如何解決這些變動呢?首先是看求最小值,這個好處理,那就是把max( )改成min( )就好了,但求最小值影響的卻不只是函數的變化,還影響了對裝滿揹包的處理。
我們知道,無論是01揹包還是完全揹包,在求揹包最大價值時處理方式都是初始化時除dp[0]=0外,其他的dp[i]都初始化爲-∞。至於爲什麼這麼處理,很多博客都有解釋,大致是說這樣處理,非法狀況(即裝不滿的狀況)都會是負值,而只有裝滿的狀態纔是正值。因爲合法狀態下的max函數都把負數給篩去了(一個正數和一個負數求max,當然取正數咯),但是若用的是min,那就的不到正確結果了,這就是爲什麼此題求最小值會給初始化帶來影響,處理方式也很簡單,就是直接將-∞改爲+∞就好了,實現+∞就是給一個題目極端狀況下都達不到的最大值。那麼變動解決了,剩下的就是完全揹包的裸題了,採用一維數組處理,若dp[n]爲+∞時,就是裝不滿的情況輸出This is impossible.其他情況輸出最小值就ok了。這題還有個小坑,就是輸出末尾的句號。(表示少打了個點wrong了5遍很蛋疼。)
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long LL;
#define inf 1000000000
LL w[10005]={0};
LL v[10005]={0};
LL dp[10005];
int main()
{
//freopen("in.in","r",stdin);
int T;
scanf("%d",&T);
while(T--)
{
memset(w,0,sizeof(w));
memset(v,0,sizeof(v));
LL a, b;
scanf("%lld%lld",&a,&b);
LL W=b-a;
dp[0]=0;
for(int i=1;i<=W;i++)dp[i]=inf;
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%lld%lld",&v[i],&w[i]);
for(int i=1;i<=n;i++)
for(int j=w[i];j<=W;j++)
dp[j]=min(dp[j],dp[j-w[i]]+v[i]);
if(dp[W]==inf)printf("This is impossible.\n");
else printf("The minimum amount of money in the piggy-bank is %lld.\n",dp[W]);
}
return 0;
}