您的位置:首页 > 其它

Exercise(3):最少硬币问题

2016-04-22 20:15 375 查看
/*
陈潼升
最少硬币问题
问题描述
设有n 种不同面值的硬币,各硬币的面值存于数组T[1:n]中。现要用这些面值的硬币来找钱。
可以使用的各种面值的硬币个数存于数组Coins[1:n]中。对任意钱数0≤m≤20001,设计一个用最少硬币找钱m的方法。
编程任务:对于给定的1≤n≤10,硬币面值数组T和可以使用的各种面值的硬币个数数组Coins,以及钱数m,0≤m≤20001,编程计算找钱m的最少硬币数。

Input
输入包括多组测试数据,每组输入的第一行中只有1 个整数给出n的值,第2 行起每行2 个数,分别是T[j]和Coins[j]。每组输入最后1 行是要找的钱数m。
Output
对于每组输入数据,输出一行,即计算出最少硬币数。问题无解时输出-1。

Sample Input
3
1 3
2 3
5 3
18
Sample Output
5

*/
/*
将一个问题分裂成n个子问题,求出子问题的解并用子问题的解出问题的答案。即为动规

问题分析 :
给m找零 可分为 找1块,找2块,找3块,找4块......找m块。
定义长度为m的数组dp[1...m],用其存放一系列子问题的结果,
即dp[i]为要凑i块钱所需最少硬币数,则dp[m]为本题答案.
当前要找的钱数为i(1<i<m);
当前所试探的硬币面值为k;
1、当i和k相等时,结果为1,即dp[i] = 1;
2、当i大于k时,若dp[i]为0(即未赋过值),且dp[i-k]不为0(即从i元中刨去k元后剩下的钱可以找开)
则dp[i] = dp[i-k]+1;
若dp[i]不为0(即已赋值),
则dp[i] = min( dp[i-k]+1, dp[i] ) 即dp[i]为dp[i-k]和dp[i]中的较小者。
3、由以上2点得dp[i]的动态转移方程为:
dp[i] = min( dp[k], dp[k-t[i]]+1 )  t[i]<=k<=m

*/
#include <iostream>
#define MAX 20001
#define MAXLEN 99999999999
using namespace std;
int min(int,int);

int main()
{
int n;                          // 输入 硬币种数并检测
cin>>n;
if(n<1 || n>10) return 0;

int *t = new int[n+1];          // t[n+1]存放各种硬币的面值
int *coins = new int[n+1];      // coins[n+1]存放各种硬币的个数

int i,j,k;                      // i,j,k为循环变量
for(i=1;i<n+1;i++)              // 输入 各种硬币面值t[i] 各种硬币个数coins[i]
{
cin>>t[i]>>coins[i];
}

int m, dp[20002];               // dp[20002]存放一系列子找零问题的结果
cin>>m;
for(i=1;i<m+1;i++)              // 因为要取最小,因此要初始化为(大大地 :drastically)数
dp[i] = MAXLEN;

dp[0] = 0;

for(i=1;i<=n;i++)               // 各种硬币
for(j=1;j<=coins[i];j++)    // 各种硬币的个数
for(k=m;k>=t[i];k--)
{                       // 动态转移方程
dp[k] = min(dp[k-t[i]]+1,dp[k]);
}

cout<<dp[m]<<endl;              // dp[m]即为所求结果
return 0;
}
int min(int a,int b)
{
return (a<b?a:b);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: