1. 程式人生 > >【杭電oj】2546

【杭電oj】2546

飯卡

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;
}