zoukankan      html  css  js  c++  java
  • 1531: [POI2005]Bank notes二进制优化(c++)

    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

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

    Sample Input

    3
    2 3 5
    2 2 1
    10

    Sample Output

    3
    解析:非常典型的多重背包,不考虑其他的,f[i][j]表示在前i种硬币下,要凑到j元最少需多少个硬币。动态转移方程为:f[i][j]=min(f[i-1][j-x[i]]+1,f[i-1][j]);(x[i]为当前硬币的价值)(当然我们可以用动态数组来优化降到一维);
    这样只要把它完全转换成01背包就可以了。可是会发现在这道题目上直接变成01会超时,所以又要用到二进制来优化!
    大家都知道,2的幂的和可以表示幂之下的任何数,比如2的5次方之下的正数,就可以用1,2,4,8,16来的任意组合的和来表示。那么对于硬币数量只要把它分成2的幂的和,就可以组成所有可能性。举个例子18可分为1,2,4,8,再加上不为2的幂的3,便可组成小于18的所有自然数,枚举所有可能性,那么原来18个选择变成了1,2,4,8,3五个选择,这不过五个选择的价值不同而已。通过这样会大大缩小01背包。好啦,具体看程序。
    #include<iostream>
    #include<cstdio>
    int num,n,k,now,t,b[40000],x[40000],y[40000],a[4000005],f[4000005];
    using namespace std;
    int min(int x,int y)
    {
        if (x>y) return y;
        return x;
    }
    int main()
    {
      cin>>n;
      num=0;
      for (int i=1;i<=n;i++) cin>>a[i];
      for (int i=1;i<=n;i++) 
      {
          cin>>b[i];//输入这种硬币的数量
          t=1;//枚举2的几次幂
          while (t*2-1<b[i])//如果目前为止枚举的所有2的幂的和小于总硬币数的话
        {
          num+=1;//数组长度
          x[num]=t*a[i];//我们就把枚举的t件物品变成一件,x储存t件原物品即现在这件物品的价值
          y[num]=t;//这件物品所代表的硬币数量
          t=t*2;//去枚举另外一个2的幂
        } 
        num+=1; 
        y[num]=b[i]-(t-1);//剩下还有几个硬币也算作一件,如举例中3这个数。
        x[num]=y[num]*a[i];//剩下这件物品的价值
      }
      cin>>k;
      //for (int i=1;i<=num;i++) cout<<x[i]<<' '<<y[i]<<endl; 
      for (int i=0;i<=k;i++) f[i]=1000000005;
      f[0]=0;
      for (int i=1;i<=num;i++)
      for (int j=k;j>=x[i];j--)//注意倒写
      f[j]=min(f[j-x[i]]+y[i],f[j]);//最好滚动数组降维
      
      cout<<f[k]<<endl;
      return 0;
    }

    恩,写完了。

  • 相关阅读:
    Android笔记之开机自启
    Android笔记之广播
    Hive笔记之collect_list/collect_set(列转行)
    Hive笔记之数据库操作
    hive笔记之row_number、rank、dense_rank
    Linux Shell管道调用用户定义函数(使shell支持map函数式特性)
    Linux shell爬虫实现树洞网鼓励师(自动回复Robot)
    分享一些免费的接码平台(国外号码)
    爬虫技能之内容提取:如何从有不可见元素混淆的页面中抽取数据
    ctf writeup之程序员密码
  • 原文地址:https://www.cnblogs.com/2014nhc/p/6209503.html
Copyright © 2011-2022 走看看