• 找硬币题解


    问题 A: 找硬币

    时间限制: 1 Sec  内存限制: 64 MB

    题目描述

    小蛇是金融部部长。最近她决定制造一系列新的货币。假设她要制造的货币的面值为x1,x2,x3… 那么x1必须为1,xb必须为xa的正整数倍(b>a)。例如 1,5,125,250就是一组合法的硬币序列,而1,5,100,125就不是。不知从哪一天开始,可爱的蛇爱上了一种萌物——兔纸!从此,小蛇便走上了遇上兔纸娃娃就买的不归路。某天,小蛇看到了N只可爱的兔纸,假设这N 只兔纸的价钱分别是a1,a2…aN。现在小蛇想知道,在哪一组合法的硬币序列下,买这N只兔纸所需要的硬币数最少。买兔纸时不能找零。

    输入

    第一行,一个整数N,表示兔纸的个数

    第二行,N个用空格隔开的整数,分别为N只兔纸的价钱

    输出

    一行,一个整数,表示最少付的钱币数。

    样例输入

    2 
    25 102 

    样例输出

    4

    提示


    样例解释:共有两只兔纸,价钱分别为25和102。现在小蛇构造1,25,100这样一组硬币序列,那么付第一只兔纸只需要一个面值为25的硬币,第二只兔纸需要一个面值为100的硬币和两个面值为1的硬币,总共两只兔纸需要付4个硬币。这也是所有方案中最少所需要付的硬币数。



       1<=N<=50, 1<=ai<=100,000

      这道题当时目测是一道数学+搜索或数学+DP题,然后默默地只打了28分。

      这道题我用的是搜索A的,但正解是DP(我竟然都猜对了,不过貌似还没有搜索快),首先一个数一定可以被分解为若干个素数的积,我们可以利用这点只去枚举素数这样能方便不少。指针恒说这道题实际就是一个秦九昭,还真是。

      我们可以得知a[i]=k[2]*x+a[i]%k[2],x为某一个常数,a[i]%b就是需要拿一块钱去补的硬币数。

      然后我们又可知a[i]-a[i]%k[2]=k[2]*x=k[3]*xx+k[2]*x%k[3]……由此我们就可以利用这点去放心大胆的去DFS第j步的余数就是使用k[j-1]的张数。什么时候被排序后的最大的a[1]为0或1了找一下就好了,至于剪枝,传统做法。

      

     1 #include<iostream>
     2 #include<cstdlib>
     3 #include<cstdio>
     4 #include<cstring>
     5 #include<queue>
     6 #include<algorithm>
     7 #include<cmath>
     8 #define N 1000005
     9 using namespace std;
    10 int n;
    11 int a[55];
    12 int bj(int a,int b){
    13     return a>b;
    14 }
    15 bool fss[N];
    16 int zz;
    17 int ss[N];
    18 void xs(){
    19     int mx=a[1];
    20     for(int i=2;i<=mx;i++)
    21     {
    22         if(!fss[i])
    23         {
    24             zz++;
    25             ss[zz]=i;
    26         }
    27         for(int j=1;j<=zz;j++)
    28         {
    29             if(ss[j]*i>mx)break;
    30             fss[ss[j]*i]=1;
    31             if(!(i%ss[j]))
    32                 break;
    33         }
    34     }
    35 }
    36 long long ans=0x7ffffff;
    37 int b[52],c[52],b2[52];
    38 inline void dfs(int wz,long long sum){
    39     //cout<<b[wz]<<endl;
    40     long long an=0;
    41     int d[52];
    42      
    43     for(int i=1;i<=n;i++)
    44     {
    45         an+=(a[i]%b[wz]);
    46         a[i]/=b[wz];
    47     }
    48     if(sum+an>=ans)return;
    49     memcpy(d,a,sizeof(a));
    50     if(a[1]!=1&&a[1]!=0)
    51     {
    52         for(int i=1;i<=zz;i++)
    53         {
    54             if(b2[wz]*ss[i]>c[1])break;
    55             b[wz+1]=ss[i];
    56             b2[wz+1]=b2[wz]*ss[i];
    57             dfs(wz+1,an+sum);
    58             b[wz+1]=0;
    59             b2[wz+1]=0;
    60             memcpy(a,d,sizeof(a));
    61         }
    62     }
    63     else
    64     {
    65         long long as=0;
    66         for(int i=1;i<=n;i++)
    67         {
    68             if(a[i])as+=1;
    69         }
    70         int la=1;
    71         for(int i=1;i<=wz;i++)
    72         {
    73             la*=b[i];
    74         }
    75         ans=min(ans,sum+an+as);
    76     }
    77 }
    78 int main(){
    79 //  freopen("coin.in","r",stdin);
    80 //  freopen("coin.out","w",stdout);
    81     scanf("%d",&n);
    82     for(int i=1;i<=n;i++)
    83     {
    84         scanf("%d",&a[i]);
    85         c[i]=a[i];
    86     }
    87     sort(a+1,a+n+1,bj);
    88     sort(c+1,c+n+1,bj);
    89     xs();
    90     b[1]=1;b2[1]=1;
    91     b[0]=1;b2[0]=1;
    92     dfs(1,0);
    93     printf("%lld
    ",ans);
    94     //while(1);
    95     return 0;
    96 }
    View Code
  • 相关阅读:
    本地搭建Nginx服务器启动web项目
    BZOJ 1815: [Shoi2006]color 有色图(Polya定理)
    即将退役选手最后的挣扎
    类欧几里得算法
    UOJ#449. 【集训队作业2018】喂鸽子(期望dp)
    Luogu P3600 随机数生成器(期望+dp)
    毒题选讲选做
    UOJ#310.【UNR #2】黎明前的巧克力(FWT)
    DZY Loves Math 系列详细题解
    项目中经常遇到的跨域请求的几种方法
  • 原文地址:https://www.cnblogs.com/liutianrui/p/7470217.html
Copyright © 2020-2023  润新知