您的位置:首页 > 其它

最少硬币问题

2009-09-24 14:32 127 查看
问题描述】有n种不同面值的硬币,各硬币面值存于数组T[1:n];现用这些面值的钱来找钱;各面值的个数存在数组Num[1:n]中。

编程任务】对于给定的1<=n<=10,硬币面值数组、各面值的个数及钱数m,0<=m<=2001,编程计算找钱m的最少硬币数。
input : 第一个数字n,后面n行每行两个数,面值T[i],面值个数Num[i];最后是钱数m。
output:最少硬币数。
Sample intput :
3
1 3
2 3
5 3
18
Sample output:
5

分析】:一看大家都会觉得最优子结构是 dp(m)=max{dp(m-t[i])+1},但是面值的个数在哪里?不好考虑。我开始以为状态跟面值、个数、钱数三个因素有关,应该要有个三维数组来存储状态,其实不然,那样的话动态规划的优势就没啦!对动态规划的理解还在“成长阶段”呀!废话少说,切入正题!
先看状态方程,状态方程一出,程序应该就ok了!
用MianZhi[1:m]和Mian_Zhi[1:m]来表示面值为i时的最少硬币数。TV[1:N]来表示某种面值的所有钱数,即TV[i]=T[i]*Num[i];

MianZhi[i]=min{MianZhi[i-T[j]*t]+t} t表示面值为T[j]的个数
T[j]<=i<=m; 2<=j<=N; (j = 1 另行考虑,动态规划必须的起点)
当j=1时 MianZhi[i]=Mian_Zhi[i]=i/T[1]; (1<=i<=m;i%T[1]==0&&i<=TV[1])
MianZhi[0]=Mian_Zhi[0]=0;

#include<iostream>
using namespace std;
int main()
{
int N,m,i,j;
cin>>N;
int *T=new int [N+1];
int *Num=new int [N+1];
int *TV=new int [N+1];
for(i=1;i<=N;i++){
cin>>T[i]>>Num[i];
TV[i]=T[i]*Num[i];
}
cin>>m;
int *MianZhi=new int [m+1];
int *Mian_Zhi=new int [m+1];

//先考虑第一种面值,作为动态规划的起始
for(i=0;i<=m;i++){
if(i<=TV[1]&&i%T[1]==0)//超过它所能组成的钱数肯定不行 i<=TV[1]
MianZhi[i]=Mian_Zhi[i]=i/T[1];
else MianZhi[i]=Mian_Zhi[i]=0;
}
//   MianZhi[0]=Mian_Zhi[0]=0; //在if里已有
//================================================
int tmpV,tmpNum,tmpN,k;
for(i=2;i<=N;i++){
for(j=T[i];j<=m;j++){
tmpN=1;//组成某种钱数需要i面值的个数
//任一面值都只能组成大于等于它的钱数,
//所以j>=T[i]
while(j>=T[i]*tmpN&&tmpN<=Num[i]){//能用到面值 T[i] 的钱数
tmpV=T[i]*tmpN;
if(j>tmpV&&MianZhi[j-tmpV]==0){
//剩余部分前面的面值不能组成
tmpN++;
continue;
}
else {
tmpNum=tmpN+MianZhi[j-tmpV];
if(tmpNum<MianZhi[j]||MianZhi[j]==0)
//前面各种面值都扫过一遍了
//MianZhi[j]==0是说明之前没有解
Mian_Zhi[j]=tmpNum;
}
tmpN++;
/*虽然找到了,但正如前面if所说的”剩余部分...“
而且面值没排序,所以可能前面还有面值大的组成的最优解
所以继续++*/
}
}
for(k=0;k<=m;k++)
MianZhi[k] = Mian_Zhi[k];//更新
}

if(MianZhi[m]==0)    MianZhi[m]=-1;
cout<<MianZhi[m]<<endl;
//===============华丽的分割线================//释放内存
delete [] T;
delete [] Num;
delete [] MianZhi;
delete [] Mian_Zhi;
delete [] TV;
system("pause");
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: