NYOJ995硬币找零

硬币找零


描述
在现实生活中,我们经常遇到硬币找零的问题,例如,在发工资时,财务人员就需要计 算最少的找零硬币数,以便他们能从银行拿回最少的硬币数,并保证能用这些硬币发工资。
我们应该注意到,人民币的硬币系统是 100,50,20,10,5,2,1,0.5,0.2,0.1,0.05,
0.02,0.01 元,采用这些硬币我们可以对任何一个工资数用贪心算法求出其最少硬币数。 
但不幸的是: 我们可能没有这样一种好的硬币系统, 因此用贪心算法不能求出最少的硬币数, 甚至有些金钱总数还不能用这些硬币找零。例如,如果硬币系统是 40,30,25 元,那么 37 元就不能用这些硬币找零;95 元的最少找零硬币数是 3。又如,硬币系统是 10,7,5,1 元,那么 12 元用贪心法得到的硬币数为 3,而最少硬币数是 2。 
你的任务就是:对于任意的硬币系统和一个金钱数,请你编程求出最少的找零硬币数;
如果不能用这些硬币找零,请给出一种找零方法,使剩下的钱最少。 

解题思路:

一开始的时候我直接深搜了一下,其实就是想调戏下OJ君:

#include<stdio.h>
#include<stdlib.h>
#define N 50
 int a[N];
 int ans;
int cmp(const void *x,const void *y){
   return *(int *)x>*(int *)y?1:-1;
}
int MinRest;
int Min(int a,int b){
   return a<b?a:b;
}
int n;
void dfs(int cur,int rest,int Count){
    if(rest<0)
        return ;
     if(rest<=MinRest){
            if(rest<MinRest)
                    ans=Count;
            else
               ans=Min(ans,Count);
            MinRest=rest;

     }
     for(int i=0;i<n;i++){
        dfs(i,rest-a[i],Count+1);
     }
}
int main()
{
    int sum;
    int i;
    while(scanf("%d%d",&n,&sum)&&(n||sum)){
        for(i=0;i<n;i++)
            scanf("%d",&a[i]);
        qsort(a,n,sizeof(a[0]),cmp);
        MinRest=sum;
        ans=1<<31-1;
        dfs(0,sum,0);
        printf("%d\n",ans);
    }
}
然后超时了,那就动规吧。

这个题有三个点:

1)所有的硬币都是无限的;

2)要用尽可能少的硬币;

3)无法找零要尽可能的靠近。

咦~~怎么有点像背包啊,给你n个物品,每个物品都一个价值和一个重量,背包有一个固定的容量。。。好吧YY一下而已啦!

构建dp[i]数组,i块钱最少需要多少个硬币。那么状态转移方程必然是(a[i]用来存那套硬币系统)dp[i]=min(dp[i-a[k]]k={0..n});

#include<stdio.h>
#include<algorithm>
#include<string.h>
#define N 100008
unsigned int dp[N];
unsigned int a[51];
unsigned int n,sum;
void Dp(){
   unsigned int min,i,j;
   for(i=1;i<=sum;i++){
      min=100008;
      for(j=0;a[j]<=i&&j<n;j++){
            if(min>dp[i-a[j]]&&(dp[i-a[j]]!=0||i==a[j]))
                 min=dp[i-a[j]];
      }
      if(min!=100008)
         dp[i]=min+1;
   }
}
int main(){
    unsigned int i;
    while(scanf("%d%d",&n,&sum)&&(sum||n)){
        memset(dp,0,sizeof(dp));
        for(i=0;i<n;i++){
            scanf("%d",&a[i]);
            dp[a[i]]=1;
        }
        std::sort(a,a+n);
        Dp();
        while(dp[sum]==0)
            sum--;
        printf("%d\n",dp[sum]);
    }

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值