動態規劃 HDU 2546 飯卡
阿新 • • 發佈:2019-01-22
在acm群裡看到了這樣的一個題目,拿過來看了一下,感覺還蠻有意思的,題目大意是飯卡上有m餘額,但是學校有個規定,飯卡餘額少於5元就不能買東西,現在有n件商品,每件商品都有一個價格。要求買好商品後餘額最少。
看到題目就想到了揹包問題,在一個m-5的揹包裡儘量裝滿東西,裝滿後放最後一個物品,解肯定在放完這個物品之後。 最直接的想法就是對放的最後這個物品進行列舉,然後用餘下的物品去裝m-5的揹包,儘量裝滿。得到的最小值就是答案。當然還要考慮餘額小於5元的情況,如果小於5元就直接輸出就行了,因為不能買東西。
思路有了,接下去是實現,n是1000,m是1000,價格不會超過50,如果列舉的話,複雜度是n*n*m,明顯會超時。由於每件商品價格不會超過50,那麼只要統計下對應價格的商品件數就行了,然後用二進位制優化。
帖程式碼:
#include <iostream> #include <algorithm> using namespace std; #define INF 0xFFFFFFF int price[55]; //統計對應價格的商品件數 int dp[1001],m; void zeroOnePack(int volume) { for (int k=m-5; k>=volume; k--) { dp[k] = max(dp[k], dp[k-volume]+volume); } } int main() { int n, p; while (cin >> n && n ) { memset(price, 0, sizeof(price)); for (int i=0; i<n; i++) { cin >> p; price[p] ++ ; } cin >> m; if (m <5) { cout << m << endl; continue; } int ans = INF; for (int i=1; i<=50; i++) { if (!price[i]) continue; price[i] --; memset(dp, 0, sizeof(dp)); for (int j=1; j<=50; j++) { if (!price[j]) continue; int total = price[j]; for (int gs=1 ; total>=gs; gs<=1, total-= gs) { zeroOnePack(gs*j); } zeroOnePack(total*j); } int tmp = m-dp[m-5]-i; if (ans > tmp) ans = tmp; price[i] ++; } cout << ans << endl; } }