1. 程式人生 > >hdoj 2546 飯卡 【01揹包】

hdoj 2546 飯卡 【01揹包】

飯卡

Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 16638    Accepted Submission(s): 5790


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

題目解析:

想要使卡上餘額最少,得保證最後一次買的菜最貴,(前提是你在最後一次買菜時卡上的前要大於或等於5)。假設購買菜之前卡上餘額為m,如果小於5元,那就不能買東西,所以卡里的錢不變;如果大於或等於5元,就用m-5表示可用餘額u,先花可用餘額,這樣就保證了在最後一次買菜前,你還有不少於5元的錢,然後用這最後的錢去買最貴的菜,就能使餘額最小了。(每買一個菜,在購買前都會先判斷餘額,不會出現一次買多個菜)。

程式碼:

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int sum[1010];//所能購買的最大價值;
int price[1010];//每個菜的價錢;
int main()
{
	int t;
	int n,i,j;//n是菜的數量;
	int m,u;//卡上的餘額,可用餘額;	
	while(scanf("%d",&n),n)
	{
		memset(sum,0,sizeof(sum));//將sum陣列初始化為0;
		for(i=0;i<n;i++)
		{
			scanf("%d",&price[i]);
		}
		sort(price,price+n);//目的是找出最貴的菜,price[n-1]是最貴的菜;
		scanf("%d",&m);
		if(m<5)//餘額小於5時跳出;
		{
			printf("%d\n",m);//因不能購買,所以卡里的錢不變;
			continue;
		}
		u=m-5;//可用餘額,用可用餘額去買除了最貴的菜的剩餘的菜,能買多少就買多少。
		for(i=0;i<n-1;i++)//(0----n-2)//除去最貴的菜的所有菜; 
		{
			for(j=u;j>=price[i];j--)
			{
				sum[j]=max(sum[j],sum[j-price[i]]+price[i]);
				//保證在餘額不少於5的情況下購買最大價值。 
			}
		}
        //運算到這裡,我們已經求出可用餘額u所能購買的最大價值sum[u]。接下
//來卡里至少還有5元,而我們最貴的菜還沒有買,這是最後一次購買機會,
//我們買最貴的菜,就能使卡里的餘額最小了。
		printf("%d\n",m-sum[u]-price[n-1]);
		//可用餘額買的最大價值(除去最大菜價),加上最大菜價就是餘額能買到的最大價值,用餘額m(最開始的餘額)減去能買到的最大價值,卡里的餘額就最小了; 
	}
	return 0;
}