原题
原题链接
题目大意
题目是讲有一个储钱罐,给出空罐时重量E,目前罐的重量F,已知罐里硬币的种类,有n种,每一种都给出其价值p[i]和重量w[i],问该罐里至少有多少钱?如果硬币不能刚好凑够该重量则输出-1.
题目解析
为了讲题方便,我把题目空罐时质量换成m0,目前罐的重量换成m,价值改成v[i].这道题可以转换为一个等效的问题,就是给定硬币种类,每种硬币有无限个,问能否从这些硬币中刚好凑成重量为m-m0的硬币堆,如果能凑的话价值之和要尽可能小.稍微思考后会发现这就是完全背包问题,只是稍微变动而已.首先设一个dp数组,dp[i]表示i重量时硬币价值之和的最小值.(初始化为INF),dp[0]=0,dp[i]=INF表示这些硬币不能凑到刚好i重量,然后一遍外循环用i=1→n遍历所有物品,内循环从j=w[i]→(m-m0)(内循环这样更新能体现出一种硬币有无限个的特点)if(dp[j-w[i]]!=INF) dp[j]=min(dp[j],dp[j-w[i]]+v[i])来不断更新dp数组,最后如果dp[m-m0]不是INF,输出dp[m-m0],否则输出-1即可.(j之所以从w[i]开始是为了防止j-w[i]越界,对这个dp还是不太清楚的话可以在草稿纸模拟这个dp数组的更新过程)
代码
1 #include2 #include 3 #include 4 #include 5 #include 6 #include 7 #include <string> 8 #include 9 #include 10 #include 11 const int INF=0x3f3f3f3f; 12 using namespace std; 13 14 int dp[10001]; 15 int w[501],v[501]; 16 17 int main() 18 { 19 int t; 20 cin>>t; 21 while(t--) 22 { 23 memset(dp,INF,sizeof(dp)); 24 memset(w,0,sizeof(w)); 25 memset(v,0,sizeof(v)); 26 int m0,m,n; 27 cin>>m0>>m>>n; 28 m-=m0; 29 for(int i=1;i<=n;i++) 30 cin>>v[i]>>w[i]; 31 dp[0]=0; 32 for(int i=1;i<=n;i++) 33 for(int j=w[i];j<=m;j++) 34 if(dp[j-w[i]]!=INF) dp[j]=min(dp[j],dp[j-w[i]]+v[i]); 35 if(dp[m]!=INF) cout<<"The minimum amount of money in the piggy-bank is "< '.'<<endl; 36 else cout<<"This is impossible."<<endl; 37 } 38 return 0; 39 }