/* 这类问题感觉叫0-1背包不知道标准不标准 * 但明确dp之后,求解方式和0-1背包基本一致 * dp[i][j]:表示前i张邮票凑成j面额所需要最少的邮票数 * (1) 选第i张 ==> dp[i][j] = dp[i-1][j-w[i]] + 1(选i所以邮票数+1) * (2) 不选第i张==> dp[i][j] = dp[i-1][j] (不选i所以邮票数不累积) * 状态转移方程: * dp[i][j] = min(dp[i-1][j],dp[i-1][j-w[i]] + 1); * 除了min之外,和0-1背包就完全一样了,因此也可以空间优化为一维dp[v] * 如果简化为一维dp,有一个问题就是初始化 * dp[0] = 0 其它dp[v]=INF * 其实这就是高赞回答里的*矩阵*,结合矩阵就会发现INF不影响后续计算 */ #include <cstdio> #include <iostream> #include <algorithm> using namespace std; const int maxV = 101; const int maxN = 21; const int INF = 1000000000; int dp[maxV]; //如果是二维dp[i][j], 其实内容是一个下三角矩阵(省略了很多行的下三角矩阵,我当前的理解,不知道对不对) int w[maxN]; int main(){ int N,V; //V即为题目中的M while(cin>>V>>N){ for(int i=0;i<N;i++){ cin>>w[i]; } fill(dp,dp+maxV,INF); dp[0] = 0; for(int i=0;i<N;i++){ for(int j=V;j>=w[i];j--){ dp[j] = min(dp[j],dp[j-w[i]]+1); } } if(dp[V]!=INF) cout<<dp[V]<<endl; else cout<<"0"<<endl; } return 0; }