飯卡
電子科大本部食堂的飯卡有一種很詭異的設計,即在購買之前判斷餘額。如果購買一個商品之前,卡上的剩餘金額大於或等於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元”的揹包去裝菜,揹包裏東西裝得越多,餘額則越少。在揹包裝滿之後,飯卡里的餘額肯定是大於等於5的,根據題意可以知道只要飯卡大於等於5元,我們就可以買任何的菜,所以最後我們可以再減去一個最貴的菜,這樣飯卡的餘額就可以最少了。所以,需要有一步找到最貴的菜。
AC代碼:
#include<stdio.h>
#include<string.h>
#define MAX 1010
int dp[MAX],cost[MAX];
int n,m;
int max,id;
int Max(int a,int b){
return a>b?a:b;
}
void Init(){
memset(dp,0,sizeof(dp));
memset(cost,0,sizeof(cost));
max = -1;
id = -1;
}
int ZeroOnePack(){
int canCost = m-5;
for(int i=0;i<n;i++){
if(i==id)
continue;
for(int j=canCost;j>=cost[i];j--){
dp[j]=Max(dp[j],dp[j-cost[i]]+cost[i]);
}
}
return dp[canCost];
}
int main(){
while(scanf("%d",&n)!=EOF&&n!=0){
Init();
//輸入
for(int i=0;i<n;i++)
scanf("%d",&cost[i]);
scanf("%d",&m);
if(m<5){//如果一開始給的錢就低於5元,那就什麼也買不了
printf("%d\n",m);
continue;
}
//m>5元則進行下面操作
for(int i=0;i<n;i++){//挑出最大的那個菜
if(max<cost[i]){
max=cost[i];
id=i;
}
}
cost[id] = -1;
//輸出
int a = ZeroOnePack();//找出最大花銷 前提爲剩下不小於5元
int v = m-a-max; //v表示最終可以到達的最小金額
printf("%d\n",v);
}
return 0;
}