硬币问题
有 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;
}Keep it simple!

浙公网安备 33010602011771号