清華機試-最小郵票數
阿新 • • 發佈:2018-04-15
不用 mes 最小 spa AC div 時間 lse n)
題目描述
有若幹張郵票,要求從中選取最少的郵票張數湊成一個給定的總值。 如,有1分,3分,3分,3分,4分五張郵票,要求湊成10分,則使用3張郵票:3分、3分、4分即可。
輸入描述:
有多組數據,對於每組數據,首先是要求湊成的郵票總值M,M<100。然後是一個數N,N〈 20,表示有N張郵票。接下來是N個正整數,分別表示這N張郵票的面值,且以升序排列。
輸出描述:
對於每組數據,能夠湊成總值M的最少郵票張數。若無解,輸出0。
示例1
輸入
10
5
1 3 3 3 4
輸出
3
解題思路
一開始看到這個題目,想到的是bfs。bfs的思路是:枚舉所有的可能性,最多有2的19次方種情況(524288種)。可以從0列到524287,一個數的二進制形式表示選或者不選這張郵票。由於對於每一個數字最多要列舉19位,所以時間復雜度大約是O(19*2^19)。比較高但是應該也是可以通過的,因為其實有一些數字不用列舉那麽多位。
後來想到可以用動態規劃來解決這個問題。如果將狀態dp[i][j]定義為前i張郵票湊成總值j所需要的最少郵票數。則狀態可以初始化為dp[i][0]=0。(其中,1<=i<N,0<=j<M)。
狀態轉移方程如下:
dp[i][j] = min(dp[i-1][j],dp[i-1][j-v[i]])。(其中,i>0,j-v[i]>=0)
同時註意判斷dp[i][j]是否等於-1。-1表示dp[i][j]無解。
代碼
#include <iostream> #include <cmath> using namespace std; int dp[20][100] = {-1}; int num[20]; int main() { cout << pow(2,19) * 19 << endl; int m,n; while(cin >> m >> n) { int ans = 20; for(int i = 0;i < n;i++) { dp[i][0] = 0; for(int j = 1;j <= m;j++) dp[i][j] = -1; } for(int i = 0;i < n;i++) cin >> num[i]; for(int i = 0;i < n;i++) { for(int j = num[i];j <= m;j++) { if(i == 0) { if(j == num[i]) dp[i][j] = 1; else dp[i][j] = -1; } else { int a = 20; if(dp[i - 1][j - num[i]] != -1) a = dp[i - 1][j - num[i]] + 1; int b = 20; if(dp[i - 1][j] != -1) b = dp[i - 1][j]; int c = min(a,b); if(c == 20) dp[i][j] = -1; else dp[i][j] = c; } } } if(dp[n - 1][m] == -1) cout << 0 << endl; else cout << dp[n - 1][m] << endl; } return 0; }
清華機試-最小郵票數