• [USACO06DEC]最少的硬币The Fewest Coins


    题目描述

    约翰在镇上买了 T 元钱的东西,正在研究如何付钱。假设有 N 种钞票,第 i 种钞票的面值为 Vi,约翰身上带着这样的钞票 Ci 张。商店老板罗伯是个土豪,所有种类的钞票都有无限张。他们有洁癖,所以希望在交易的时候,交换的钞票张数尽可能地少。请告诉约翰如何恰好付掉 T 元,而且在过程中交换的货币数量最少。

    输入格式

    • 第一行:两个整数 N 和 T,1 ≤ N ≤ 100, 1 ≤ T ≤ 10000

    • 第二行:n个整数 Vi 第三行:n个整数 Ci,1 ≤ Vi ≤ 120, 0 ≤ Ci ≤ 10000

    输出格式

    单个整数:表示付钱找零过程中交换的最少货币数量,如果约翰的钱不够付账,或老板没法找 开零钱,输出 −1。

    样例输入

    3 70

    5 25 50

    5 2 1

    样例输出

    3

    【题目 https://www.luogu.org/problemnew/show/2851】(蒟蒻不会弄链接,望大佬指点orz)

    题解

    易证,要求交换的货币数量最少,那么约翰付给罗伯的货币数最少,罗伯找给约翰的货币也最少。不妨分开来算。

     

    设约翰身上总共有tot元钱,那么罗伯最多找给约翰tot-T元钱。现在我们知道罗伯有哪几种面值的钞票,以及他最多需要用这些钞票凑出的总额,而每种面值的钞票都有无限张,我们就可以求出罗伯凑出1~(tot-T)元钱分别需要的最少的货币数。这就是完全背包。

     

    解决了罗伯,约翰也就比较简单了。

     

    同样的,我们知道约翰有哪几种面值的钞票,以及每种钞票的数量,显然,约翰最多可以付tot元,和解决罗伯的方法类似,我们可以求出约翰凑出1~tot元钱分别需要的最少的货币数。多重背包出现了……

     

    由于数据较大,多重背包要有二进制优化。否则会TLE!

     

    还有,由于这两个背包都要恰好装满,要把数组初始化为无穷大。

     

    最后,枚举约翰付的钱数,计算约翰需要付的最少货币数和罗伯需要找的最少货币数之和,求最小值。

    #include <cstdio>
    int n,T,w[105],c[105],v[1000005],g[1000005],f[1000005],t,tot,maxw;
    const int inf=1e9;
    int min(int x,int y)
    {
        return x<=y?x:y;
    }
    int main()
    {
        int i,j,k;
        scanf("%d%d",&n,&T);
        for (i=1;i<=n;i++)
          scanf("%d",&w[i]);
        for (i=1;i<=n;i++)
        {
            scanf("%d",&c[i]);
            tot+=w[i]*c[i];  
            if (w[i]>maxw) maxw=w[i];
        }  
        if (tot<T) 
        {
            printf("-1");
            return 0;
        }
        maxw=(maxw*maxw+T);
        for (i=1;i<1000005;i++)
          g[i]=f[i]=inf;  
        for (i=1;i<=n;i++)
          for (j=w[i];j<=maxw;j++)
            g[j]=min(g[j],g[j-w[i]]+1);
        for (i=1;i<=n;i++)
        {
            for (j=1;j<=c[i];j<<=1)
            {
                for (k=maxw;k>=j*w[i];k--)
                  f[k]=min(f[k],f[k-j*w[i]]+j); 
                c[i]-=j;  
            }
            if (c[i])
              for (j=maxw;j>=c[i]*w[i];j--)
                f[j]=min(f[j],f[j-c[i]*w[i]]+c[i]);     
        }
        int ans=inf;
        for (i=T;i<=maxw;i++)     
          ans=min(ans,f[i]+g[i-T]);
        if (ans<inf) printf("%d",ans);
        else printf("-1");
        return 0;         
    } 
  • 相关阅读:
    codevs1004 四子连棋
    codevs1009 产生数
    NOIP2014 寻找道路
    Tyvj1139 向远方奔跑(APIO 2009 抢掠计划)
    随机算法
    线性基
    线性基入门
    线性基 + 并查集
    欧拉公式 (平面)
    卡特兰数 + 大数
  • 原文地址:https://www.cnblogs.com/rabbit1103/p/7794046.html
Copyright © 2020-2023  润新知