飯卡(01背包問題)
阿新 • • 發佈:2017-08-14
是不是 panel string 無法 int nds 數量 content class
某天,食堂中有n種菜出售,每種菜可購買一次。已知每種菜的價格以及卡上的余額,問最少可使卡上的余額為多少。
網上分析:
設余額為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(inta,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背包問題)