1. 程式人生 > >飯卡(01背包問題)

飯卡(01背包問題)

是不是 panel string 無法 int nds 數量 content class

網上分析:

設余額為m,令s=m-5,那麽我們就要找使得容量為s的背包最後剩的空間最小的方法,找到之後再用這個剩余容量+5-最大的那個沒有被選的商品價值就是最小余額.

但是現在我們不知道最後需要減的那個物品應該是哪個,可以證明最後需要減的那個物品一定是價值最大的那個.證明:

假設價值最大的為max,且我們假設存在最優的情況(使余額最小)下max物品不是最後一個被減的,最後一個被減的商品價值為mid,假設此時的余額為x.那麽仔細想想如果我們把max和mid的位置互換,依然可以得到余額為x.(仔細想想是不是)

個人心得:這麽經典簡單的背包問題都懵逼了,真的是沒誰了。不過確實腦瓜子不夠機靈,你想呀,直接DP的花邊界難確定還有負數,這樣把5單獨拿出來,

就可以完全轉化為背包問題了,其實一開始拿出來後我還是很懵逼的,後面轉念一想,拿出來後裝最大值然後相減不就剩下的最小余額了嗎,真的是一道好題。

真的是水得不行。

電子科大本部食堂的飯卡有一種很詭異的設計,即在購買之前判斷余額。如果購買一個商品之前,卡上的剩余金額大於或等於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
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<cstring>
 5 #include<iomanip>
 6 #include<algorithm>
 7 using namespace std;
 8 const int maxn=1005;
 9 int n,sum;
10 int cai[1005];
11 bool cmp(int
a,int b) 12 { 13 return a>b; 14 } 15 int ways[1005]; 16 int main() 17 { 18 while(cin>>n&&n!=0){ 19 for(int i=1;i<=n;i++) 20 cin>>cai[i]; 21 cin>>sum; 22 sort(cai+1,cai+n+1); 23 if(sum<5) 24 cout<<sum<<endl; 25 else { 26 int ends=5-cai[n]; 27 sum=sum-5; 28 memset(ways,0,sizeof(ways)); 29 for(int i=1;i<=n-1;i++) 30 for(int j=sum;j>=cai[i];j--) 31 ways[j]=max(ways[j],ways[j-cai[i]]+cai[i]); 32 cout<<sum-ways[sum]+ends<<endl; 33 } 34 35 } 36 return 0; 37 }



飯卡(01背包問題)