找换硬币问题
找换硬币问题有些硬币组合是可以用贪心算法解决的,有些硬币组合是不能用贪心算法解决的。比如1,3,4 现在要找6分钱,贪心解是4,1,1共三枚,其实只需要3,3两枚。
这道题目是用动态规划解的,本质上就是完全背包。
完全背包问题定义 & 基本实现
问题:有个容量为V大小的背包,有很多不同重量weight[i](i=1..n)不同价值value[i](i=1..n)的货物,每种物品有无限件可用,想计算一下最多能放多少价值的货物。
这个问题不是求最多能放多少价值的东西,而是求达到钱数m的最少硬币数量,每种硬币无限取,有点类似于恰好转满背包。假如每种硬币数量有限的话,那就可以转化成多重背包了。
基本思路是:
F[i][s]=min{ f[i-1][s-k*coin[i]]+k|0=<s-k*coin[i] } coin[i]表示的是硬币集合
最终的状态是:F[N][S]。
0(VN)的算法:
使用一维数组
for i=1..N
for v=0..S
f[v]=min{ f[v],f[v-coin[i]]+1 }
对应的状态转移方程可以表示为:
F[i][s]=min { f[i-1][s],f[i][s-coin[i]]+1 }
i-1表示为前一次循环的结果,也就是I当前没取
参考:背包九讲
#include <stdio.h>
#include<string.h>
int coin[20]={1,2,5,10,50,100};
int pay[3000];
void printf_coin(int s,int *pay){
for(int j=0;j<6;j++){
if(s>=coin[j]&&pay[s]==(pay[s-coin[j]]+1))
{
//是s大于不要误写成pay[s];
printf("%d 钱一枚\n",coin[j]);
printf_coin(s-coin[j],pay);
break;
}
}
}
void main(){
for(int i=1;i<3000;i++)
pay[i]=1000000;//初始化的时候用memset根本就不行的,
//什么情况开始memset不行
// memset(pay,1000000,sizeof(pay));
pay[0]=0;
int s;
while(1){
printf("请输入钱数\n");
scanf("%d",&s);
int temp=0;
for(int i=0;i<6;i++){
for(int j=1;j<=s;j++){
if(j-coin[i]>=0){
//,假如就判断IF(j-coin[i])是不行的的
//会回到pay[0],所以一定要
temp=pay[j-coin[i]]+1;
pay[j]=pay[j]>=temp?temp:pay[j];
//printf("%d %d \n",j,pay[j]);
}
}
}
printf("%d 最少硬币数目是 %d\n",s,pay[s]);
printf_coin(s,pay);
}
getchar();
getchar();
}