zoukankan      html  css  js  c++  java
  • POI2005Bank notes银行货币

    Description

         Byteotian Bit Bank (BBB) 拥有一套先进的货币系统,这个系统一共有n种面值的硬币,面值分别为b1, b2,..., bn. 但是每种硬币有数量限制,现在我们想要凑出面值k求最少要用多少个硬币.

    Input

        第一行一个数 n, 1 <= n <= 200.

        接下来一行 n 个整数b1, b2,..., bn, 1 <= b1 < b2 < ... < b n <= 20 000,

        第三行 n 个整数c1, c2,..., cn, 1 <= ci <= 20 000, 表示每种硬币的个数.

        最后一行一个数k – 表示要凑的面值数量, 1 <= k <= 20 000.

    Output

        第一行一个数表示最少需要付的硬币数

    Solution

        典型的多重背包,用f[i][j]表示在前i种硬币下,要凑到j元最少需多少个硬币。动态转移方程为:f[i][j]=min(f[i-1][j-v[i]]+1,f[i-1][j])。

        但是,这道题有可能有多个硬币,所以可能会超时,所以用到一种神奇的优化,二进制优化。比如可以用1,2,4,8,5(20-1-2-4-8=5)这5个数进行组合并相加,来得到20以内的任何数。比如说用N个一元,就能把它们合并成面值为1,2,4...等log2N+1个等效硬币,原来N个01的选择变成了log2N+1个,大大降低了时间复杂度。

    Code

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstdlib>
     4 int b[4000],w[4000],v[4000],f[4000100];
     5 using namespace std;
     6 int main()
     7 {
     8     int n,num=0,t,c; 
     9     cin>>n;
    10     for (int i=1; i<=n; i++) 
    11       cin>>b[i];
    12     for (int i=1; i<=n; i++) 
    13     {
    14       cin>>c;
    15       t=1;
    16       while (t*2-1<c)//把等值的硬币拆分成几堆
    17       {
    18         num++;
    19         w[num]=t;
    20         v[num]=b[i]*t;
    21         t=t*2;
    22       } 
    23       num++; 
    24       w[num]=c-(t-1);
    25       v[num]=b[i]*w[num];
    26     }
    27     int k;
    28     cin>>k;
    29     for (int i=1; i<=k; i++) 
    30       f[i]=2100000000;
    31     f[0]=0;
    32     for (int i=1; i<=num; i++)
    33       for (int j=k; j>=v[i]; j--)
    34         f[j]=min(f[j-v[i]]+w[i],f[j]); 
    35     cout<<f[k]<<endl;
    36     return 0;
    37 }

    Source

        http://www.lydsy.com/JudgeOnline/problem.php?id=1531

  • 相关阅读:
    【经典】仙岛求药(一)
    6月份学习记录
    YZM的全排列
    最长公共子序列的长度
    20612统计八连块
    积木城堡
    不同组合数求和
    50136142WXY的百度地图
    50095106扔核弹
    【其他】关于海岛帝国互测系列赛总结
  • 原文地址:https://www.cnblogs.com/Patrick-X/p/6233781.html
Copyright © 2011-2022 走看看