有 n 种硬币,面值分别为V1,V2,V3...Vn ,每种都有无限多。给定非负整数 S ,可以选用多少个硬币,使得面值之和恰好为 S ?输出硬币数目的最小值和最大值。
记忆化搜索:
#include <iostream> #include <cstring> using namespace std; #define MAX 20005 int n, dp[MAX], vis[MAX], v[MAX]; int dp_max(int s) { if(vis[s]) return dp[s]; vis[s] = 1; int &ans = dp[s]; ans = -1 << 30; for(int i = 1; i <= n; i++) { if(s >= v[i]) { ans = max(ans, dp_max(s - v[i]) + 1); } } return ans; } int dp_min(int s) { if(vis[s]) return dp[s]; vis[s] = 1; int &ans = dp[s]; ans = 1 << 30; for(int i = 1; i <= n; i++) { if(s >= v[i]) { ans = min(ans, dp_min(s - v[i]) + 1); } } return ans; } void print_ans(int s) { for(int i = 1; i <=n; i++) { if(s >= v[i] && dp[s] == dp[s - v[i]] + 1) { cout << i << " "; print_ans(s - v[i]); break; } } } int main() { freopen("in.txt", "r", stdin); int s; cin >> n >> s; for(int i = 1; i <= n; i++) { cin >> v[i]; } memset(dp, 0, sizeof(dp)); memset(vis, 0, sizeof(vis)); vis[0] = 1; cout << "max = " << dp_max(s) << endl; print_ans(s); cout << endl; memset(dp, 0, sizeof(dp)); memset(vis, 0, sizeof(vis)); vis[0] = 1; cout << "min = " << dp_min(s) << endl; print_ans(s); cout << endl; return 0; }
递推实现:
#include <iostream> #include <cstring> #include <algorithm> using namespace std; #define MAX 1000 #define INF (1 << 30) int Max[MAX], Min[MAX], v[MAX]; int n; void print_ans(int *dp, int s) { for(int i = 1; i <= n; i++) { if(s >= v[i] && dp[s] == dp[s - v[i]] + 1) { cout << i << " "; print_ans(dp, s - v[i]); break; } } } int main() { freopen("in.txt", "r", stdin); int s; cin >> n >> s; for(int i = 1; i <= n; i++) { cin >> v[i]; } Min[0] = Max[0] = 0; for(int i = 1; i <= s; i++) { Min[i] = INF; Max[i] = -INF; } for(int i = 1; i <= s; i++) { for(int j = 1; j <= n; j++) { if(i >= v[j]) { Min[i] = min(Min[i], Min[i - v[j]] + 1); Max[i] = max(Max[i], Max[i - v[j]] + 1); } } } cout << "min = " << Min[s] << endl; print_ans(Min, s); cout << endl; cout << "max = " << Max[s] << endl; print_ans(Max, s); cout << endl; return 0; }