【杭電oj】2546
阿新 • • 發佈:2019-02-08
飯卡
Time Limit: 5000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 20176 Accepted Submission(s): 7027
Problem Description 電子科大本部食堂的飯卡有一種很詭異的設計,即在購買之前判斷餘額。如果購買一個商品之前,卡上的剩餘金額大於或等於5元,就一定可以購買成功(即使購買後卡上餘額為負),否則無法購買(即使金額足夠)。所以大家都希望儘量使卡上的餘額最少。
某天,食堂中有n種菜出售,每種菜可購買一次。已知每種菜的價格以及卡上的餘額,問最少可使卡上的餘額為多少。
Input 多組資料。對於每組資料:
第一行為正整數n,表示菜的數量。n<=1000。
第二行包括n個正整數,表示每種菜的價格。價格不超過50。
第三行包括一個正整數m,表示卡上的餘額。m<=1000。
n=0表示資料結束。
Output 對於每組輸入,輸出一行,包含一個整數,表示卡上可能的最小余額。
Sample Input 1 50 5 10 1 2 3 2 1 1 2 3 2 1 50 0
Sample Output -45 32
Source
還是01揹包問題,只是題目有個條件——錢數小於5的時候,不能買東西。這點注意一下。
如果初始錢數就小於5,則不買任何東西,直接輸出當前錢數。
如果初始錢數大於等於5,則先把那5塊騰出來買最貴的東西,然後對剩餘的物品用01揹包的方法就行了。
程式碼如下:
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; int main() { int n,v; int c[1111]; int dp[1111]; while (~scanf ("%d",&n) && n) { memset (dp,0,sizeof (dp)); for (int i = 1 ; i <= n ; i++) scanf ("%d",&c[i]); scanf ("%d",&v); if (v < 5) //特判一下 { printf ("%d\n",v); continue; } sort (c + 1 , c + n + 1); for (int i = 1 ; i < n ; i++) { for (int j = v - 5 ; j >= c[i] ; j--) //留出5塊錢買最貴的 { dp[j] = max (dp[j] , dp[j-c[i]] + c[i]); } } printf ("%d\n",v - dp[v-5] - c[n]); } return 0; }