题目:有n种硬币,面值分别为V1,V2,…Vn,每种都有无限多。给定非负整数S,可以选用多少个硬币,使得面值之和恰好为S?输出硬币数目的最小值。
思路:
定义d[s]为面值s到面值0最少可用的硬币数目
状态转移方程:d[s] = max(d[s - v[i]] + 1),其中s >= v[i];
代码:
#include <iostream>
#include <string>
using namespace std;
int n, S, V[MAXN], d[MAXN], vis[MAXN];
const int MAXN = 10000;
const int INF = 100000000;
int dpmax(int S) {
if(vis[S]) return d[S];
vis[S] = 1;
int &ans = d[S];
ans = -1 << 30;
for(int i = 1; i <= n; ++i) {
if(S >= V[i]) ans = max(ans, dpmax(S - V[i]) + 1);
}
return ans;
}
int dpmin(int S) {
if(vis[S]) return d[S];
vis[S] = 1;
int &ans = d[S];
ans = -1 >> 30;
for(int i = 1; i <= n; ++i) {
if(S >= V[i]) ans = min(ans, dpmin(S - V[i]) + 1);
}
return ans;
}
int main() {
memset(vis, 0, sizeof(vis));
cin >> n >> S;
for(int i = 1; i <= n; ++i) {
cin >> V[i];
}
cout << dpmax(S) << endl;
cout << dpmin(S) << endl;
return 0;
}