poj 1742 Coins 【多重背包+二进制拆分优化】

POJ1014-Dividing【DFS】【多重背包+二进制优化】 北大POJ1014-Dividing【DFS】【多重背包+二进制优化】 解题报告+AC代码 立即下载

 

Coins

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 3969    Accepted Submission(s): 1578


 

Problem Description

Whuacmers use coins.They have coins of value A1,A2,A3...An Silverland dollar. One day Hibix opened purse and found there were some coins. He decided to buy a very nice watch in a nearby shop. He wanted to pay the exact price(without change) and he known the price would not more than m.But he didn't know the exact price of the watch.

You are to write a program which reads n,m,A1,A2,A3...An and C1,C2,C3...Cn corresponding to the number of Tony's coins of value A1,A2,A3...An then calculate how many prices(form 1 to m) Tony can pay use these coins.


 

Input

The input contains several test cases. The first line of each test case contains two integers n(1 ≤ n ≤ 100),m(m ≤ 100000).The second line contains 2n integers, denoting A1,A2,A3...An,C1,C2,C3...Cn (1 ≤ Ai ≤ 100000,1 ≤ Ci ≤ 1000). The last test case is followed by two zeros.


 

Output

For each test case output the answer on a single line.


 

Sample Input


 

3 10 1 2 4 2 1 1 2 5 1 4 2 1 0 0

 

Sample Output


 

8 4

 

 

 

题意:给面值不同,有固定个数的硬币,能有多少种不同的不同总面值的组合方式;

思路:把多重背包问题用二进制拆分成 01 背包求解,再加上一点剪枝;

先解释一下多重背包如何优化,这里有一个数学的结论: 1到n以内的数字,能够通过 n 内的进制数组合得到,比如 9以内的二进制数有 1 2 4 8,可以自己在草稿纸上试一下, 3能通过 1 + 2 得到,5能通过1 + 4 得到,6能通过 2 + 4得到,所以,我们可以利用二进制数的拆分求出所有 n 以内的数;下面是拆分的过程:

9 - 1 = 8;  8 - 2 = 6; 6 - 4 = 2 ; 2 - 8  < 0; 那么要求的 9 以内的二进制数就是  1,2, 4,2,这几个二进制是能够组成 9以内包括 9 的所有整数,然后通过 w[ i ] 乘以这些二进制数,把他们当作一件物品来做01背包的处理,当然,如果没有用二进制拆分的话,可以直接把9拆分成  1,2,3,4,5,6,7,8,9 然后乘以w[ i ] 当作一件物品来做01背包处理,这种依次拆分的时间复杂度和不拆直接用多重背包处理是一样的,但是,为什么9个数字,只需要1,2,4,2这四个二进制数就够了呢?(这个问题暂时还没办法解决,能力有限,目前只要知道,只要拆分的二进制数字能够组成 n 以内的所有数的情况下,转化为单个物品做01背包的处理就行了),下面是代码:

 

#include<iostream>
#include<cstdio>
#include<cstring>

using namespace std;

#define Maxn 100010
#define INF 0x3f3f3f3f

int dp[Maxn],v[105],num[105],tmp_v[Maxn],book[Maxn];

int main(void)
{
   // freopen("in.txt","r",stdin);
   // freopen("out.txt","w",stdout);
    int kind,max_p;
    while (scanf("%d%d",&kind,&max_p) != EOF) {
        if(!kind && !max_p) break;
        for (int i = 1; i <= kind; ++i) scanf("%d",&v[i]);
        for (int i = 1; i <= kind; ++i) scanf("%d",&num[i]);

        memset(dp,0,sizeof(dp));
        
        int cnt = 1;  // 用单独的数组存取拆分后的所有面值
        for (int i = 1; i <= kind; ++i) {
            for (int j = 1; j <= num[i]; j <<= 1) {
                tmp_v[cnt] = j*v[i];
                num[i]-=j;
                cnt++;
            }
            if(num[i] > 0) tmp_v[cnt++] = num[i]*v[i];
        }
        
        //用上面拆分后的数组做01背包的处理
        // 这里并没有用01背包去求最大值,而是把能够满足条件的状态dp 赋值为1,下标就是能够组合得到的总面值,
        //否则为 0 ,不存在这样的面值
        memset(book,0,sizeof(book));
        int max_ = 1;  
        int ans = 0;
        for (int i = 1; i < cnt; ++i) {
                max_+=tmp_v[i];
                max_ = min(max_p,max_);
            for (int j = max_; j >= tmp_v[i]; --j) {   //j的循环做了一些剪枝,因为遍历是从右往左的,在纸上模拟一下
                if(dp[j]) continue;                     //就会明白,当前j遍历的最大值就是把以前用过的面值的累加,最小值就是
                if(j == tmp_v[i]) dp[j] = 1;            //当前物体的面值;
                else if(j-tmp_v[i] > 0 && dp[j-tmp_v[i]]) dp[j] = 1;
                if(!book[j] && dp[j]) { ans++; book[j] = 1; }
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}

 

 

 

N天后,对上面的代码进行改进,同样的一道题,要不是遇到poj,我可能以为上面的代码就很完美了,事实上,上面的代码如果交的poj的coins的话,会时间超限,而上面的代码只能在HDU的题库上AC,不得不说,这题的数据测试上,poj要强HDU很多,下面看看两个能在poj  AC的代码,第一种的用时是 2800ms左右,这里的方法其实和上面的是一样的,只是在一些个别数据上面加上了完全背包来优化了时间;方法:针对一些硬币的数量,我们把他们统一做二进制拆分然后做01背包处理,假设一种硬币的数量为 10^5,那么二进制拆分得到的单个物品的数量就是  log 2(10^5),不做常数优化的01背包的情况下,一个数量为10^5的硬币时间复杂度大概就是  15*V  (V是硬币组合的最大值),假设V是题目的上限 10^5,那么单个硬币的时间复杂度就是1.5*10^6,算是比较大的了,一般时间复杂度为 10^8 为比较适合的;对于这类数量巨大的数据我们如何处理? 其实仔细想想,但凡硬币的数量*硬币的价值的总和大于规定的 V 的时候,我们是不是可以直接把他当做完全背包处理,如果用完全背包的话,一个物品不用拆分就能完成这个硬币的dp操作,时间复杂度为一个V,单个数据就能快上15倍这个样子,完全背包的特点就是物品的数量可以无限取,但事实上,物品的数量*物品的价值大于规定的V的值得时候,我们是直接不考虑的;所以和上面的代码不同的就是,把硬币的数量分成两类,一类就是数量*面值大于 V的,把他当做完全背包处理,小于或者等于的话,就继续做上面代码的二进制拆分的01背包处理;下面给出代码:

 

#include<cstdio>

using namespace std;

#define Maxn 100010

int dp[Maxn],N,V,price[105],num[105];

void com_beg(int x) {   // 完全背包
    for (int j = price[x]; j <= V; ++j) {  // 这里 j=price[x] ,是一点剪枝,建议自己独立思考一下,
                                            // 为什么这样剪枝
        if(!dp[j] && j >= price[x] && dp[j-price[x]]) dp[j] = 1;
    }
}

void zero_one (int x) {  // 01背包
    for (int j = V; j > 0; --j) {  
        if(j < x) break;
        if(!dp[j] && dp[j-x]) dp[j] = 1;
    }
}

int main(void)
{
    while (scanf("%d%d",&N,&V) != EOF) {
        if(!N && !V) break;
        for (int i = 0; i < N; ++i) scanf("%d",&price[i]);
        for (int i = 0; i < N; ++i) scanf("%d",&num[i]);
        for (int i = 1; i <= V; ++i) dp[i] = 0; // 这里初始化是可以用memeset的,但数组开的大
        dp[0] = 1;                              // 这样也许会快一丢丢把。。
        // 这里dp[0] 其实是一个确切的值,想想,背包数量为0的时候,不放不就满足条件了吗
        for (int i = 0; i < N; ++i) {
            if(num[i]*price[i] >= V) {
                com_beg(i);
            }
            else {
                for (int j = 1; j <= num[i]; j <<= 1) {
                    if(j*price[i] <= V) zero_one (j*price[i]);
                    num[i]-=j;
                }
                if(num[i] > 0 && num[i]*price[i] <= V) zero_one(num[i]*price[i]);
            }
        }
        int ans = 0;
        for (int i = 1; i <= V; ++i) if(dp[i]) ans++;
       printf("%d\n",ans);
    }
    return 0;
}

 

上面就是其中的一种写法,但时间还是花费有点多,第二种方法有一个(好像很牛B的名字)多重背包可行性的名字;下面我解释一下这种方法是怎样的一个原理(是我自己理解的,也许不对,可以看看参考一下);

多重背包与完全背包和01背包最大的不同就是有限定的数量,也就是说,每一种物品限定的数量是不定的,我们回想一下最基本的多重背包是如何写的: 在01背包的基础上,多加一个循环k,k的作用就是一个限制的作用,当k 大于当前物品的数量的时候就退出,然后下一个又继续;如果我们能用别的方法代替这个k去限定物品的数量,也许就可以把这个k的循环去掉了;多重背包可行性的问题其实是一个系列的问题,都是问你一个物品能有多少种组合,而不是问你最大重量或者最小重量是多少,对于01背包和完全背包的问题上,我们用dp来表示当前的状态,并且把当前的子问题的答案存储到dp数组里头,比如,我们要求最大值,那么就把当前状态的子问题的最大值放进dp里面,那这道coins的子问题只是问我们能否组合得到,所以,可以用0和1来表示是或者否,而多重背包可行性的问题就是利用了这一点,把硬币的数量值放在dp里头,把dp的数据用一个特别的值隔开,一边表示能组合一边表示不能,而且这个数据同时还能够存储硬币的数量,来限定这个硬币的使用;下面有几张图:

 

假设硬币有 两种 kind 1 和 kind 2;kind 1 的价值为1,另一个为2,数量分别为 2 和 3,V的值是6,dp【j】的j值表示的意思和上面的一样,就是罐子里面硬币的总值;

kind 1 的情况,kind 1 是第一个放入的,所以毫无疑问,能组合的总值就是kind 1 的倍数,我们一维 dp 初始化为 0 ,表示的是硬币还一次没用,当 j的 1的时候,罐子内是可以放一枚 kind 1 硬币的,然后在dp + 1,表示用了一枚了,并且用另外一个数值来存能够满足条件的组合,就是book[ 1 ] = 1; 然后 j = 2 的时候,dp【2】 == 0 && book【2】 == 0  ,说明硬币总值为 2 的罐子还没出现过(这里要注意,我们每次一个硬币只放一个),然后我们找 dp【j - price[ 1 ]】也就是 dp [ 2 - 1 ] ,发现是存在这种总值的罐子,那么我们直接在这个罐子里面投一枚  kind 1 ,就能得到 j = 2,硬币总值为 2  的罐子了,然后dp 【2】 = dp【1】+ 1;为什么 + 1?这里 + 1的意思是完成 j = 2 的时候用了已经有一枚kind 1 的总值为 1 的罐子:

 

 

既然dp【2】 已经到kind 1 数量的上限了,是不是就意味着j = 2 后面就不用遍历了呢?并不是,下面看看 kind 2 的情况就明白了:

 

 

我们先看 j = 2 的时候,j = 2的时候,显然上一次就已经用 book 记录了 book【2】 == 1;也就是说,即使不加kind 2的硬币,也能组合得到 j == 2 的罐子,所以不用放一枚kind 2 硬币,然后我们在看 j = 3 的时候,显然 book【3】 == 0,就去看dp【j - price【2】】的值,也就是 dp【3 - 2】 = dp 【1】,显然 book【1】 == 1 && dp【1】 == 0,如果当前dp【1】 == 0,说明在不用kind 2硬币的情况下存在 j == 1的罐子的组合,那么我们在 j = 1 这个罐子里头放一个  kind 2 的硬币,那就能够有j = 3 的罐子了,这里我们只用了一枚 kind 2的硬币,因为组合得到的 j = 1的罐子没用kind 2的硬币(判断dp【1】就能知道),j = 4也是一样的道理,j = 5的时候,发现book【5】== 0;那么我们就找 book【3】,book【3】= 1,注意,上图中第一行虽然dp【3】 == 0,但是在第二行的dp【3】是不为0的,说明存在j = 3的罐子,这时候发现dp【3】 = 1,说明组合得到 j = 3的时候用了一枚,那么组合得到dp【5】的时候就应该dp【5】 = dp【3】 + 1;这时候dp【5】 = 2;说明组合dp【5】用了2了两枚kind 2的硬币,以此类推,如果dp【j】大于当前硬币的数量的时候,就能直接判断不可行了;下面给出代码:

 

#include<cstdio>
#include<cstring>

using namespace std;

#define Maxn 100010

int dp[Maxn],N,V,price[105],num[105],book[Maxn];

int main(void)
{
    while (scanf("%d%d",&N,&V) != EOF) {
        if(!N && !V) break;
        for (int i = 1; i <= N; ++i) scanf("%d",&price[i]);
        for (int i = 1; i <= N; ++i) scanf("%d",&num[i]);
        for (int i = 0; i <= V; ++i) dp[i] = 0;
        memset(book,0,sizeof(book));
        book[0] = 1; //  0这种组合是无论如何都存在的

        for (int i = 1; i <= N; ++i) {
            for (int k = 1; k <= V; ++k) dp[k] = 0;
            for (int j = price[i]; j <= V; ++j) {
                if(!book[j] && book[j - price[i]] && dp[j-price[i]] < num[i]) {
                    dp[j] = dp[j-price[i]] + 1;
                    book[j] = 1;
                }
            }
        }
        int ans = 0;
        for (int i = 1; i <= V; ++i) if(book[i]) ans++;
       printf("%d\n",ans);
    }
    return 0;
}

 

 

 

 

 

 

 

 

低速信号设计之 ESPI 篇 ESPI 是 Intel 推出的增强型串行外设接口,基于 SPI 发展而来,新增 Reset# 和 Alert# 信号,采用点对点主从通信模型,最高速率达 33MHz,支持半双工与 DMA 传输。 其物理接口含 10 条线路,通信协议分物理层、数据链路层等四层。布局布线需关注信号完整性、电源完整性,还得考虑与 SPI 的兼容性。 ESPI 广泛应用于计算机系统(连接 BIOS、电源管理器等)和工业控制领域,具有引脚少、功耗低等优势,但设计复杂且存在兼容性挑战。 阅读详情

相关推荐

海康视觉平台VisionMaster实战入门:从通讯配置到工具应用

本文为海康VisionMaster视觉平台实战入门指南,详细介绍了从软件安装准备、与PLC等外部设备的通讯配置,到匹配定位、测量、畸变矫正等核心工具的应用方法。通过实战案例拆解,帮助工程师快速掌握如何搭建完整的机器视觉检测与引导定位系统,实现工业自动化项目落地。

weixin_29224309的博客 1006

AcWing 5:多重背包问题 II ← 二进制优化

本题中,每种物品最多 2000 件。依据二进制优化的思想,可将 2000 分解为 2000=1+2+4+…+2^9+C,即每种物品最多拆分成 11 堆。又由于题目给出的物品种数的上限为 1000,因此二进制优化后最多有 11×1000 堆物品(也即多重背包二进制优化后对应的物品总数)。

hnjzsyjyj的专栏 1万+

Rockchip平台之RK3566/3568 OS02N10

文章摘要 本文主要介绍了200W摄像头传感器OS02N10在RK3566平台上的兼容与适配过程。作者基于之前的400W摄像头兼容经验,针对200W摄像头进行了类似的适配工作。文章详细阐述了RK3566芯片的特性和OS02N10传感器的技术参数,包括分辨率、接口和功耗等。适配过程分为三个关键部分:DTS设备树文件配置(定义I2C地址、电源域和GPIO控制等)、驱动文件开发(寄存器初始化和操作)以及XML和JSON配置文件调整(图像参数设置)。作者特别强调了初始化数组中空寄存器终止条件的重要性,并分享了兼容过程

different_xzh的博客 2412

多重背包问题--二进制优化

特征:每个物品的个数有限 集合划分跟完全背包一样,只不过k有上限s[i] 一、暴力解法 import java.util.Scanner; public class Main{ public static void main(String[] args) { Scanner in = new Scanner(System.in); int N = in.nextInt(); int V = in.nextInt(); int[] v =

qq_46689648的博客 2196

车载以太网抓包实战:100BASE-T1/1000BASE-T1高效监控方案解析

本文深入解析了车载以太网100BASE-T1/1000BASE-T1的高效抓包监控方案。针对智能汽车开发中的故障排查与性能测试需求,详细对比了交换机镜像、TAP分流和捕获模块三大主流方案的原理、核心优势与适用场景,并提供了基于实战经验的选型指南与操作避坑要点,帮助工程师精准定位网络问题。

desk3的博客 426

如何实现SOLIDWORKS阵列的“智能变更”?

有时,我们在设计一个零件时,零件上有一排阵列孔,同时零件有不同的长度,我们又希望可以做到零件长度改变时,这排孔可以按长度等距增减孔阵列的个数;或是零件长度加长或缩短时,这排孔保持个数不变,按零件长度增减孔距。 那具体要怎么做呢?接下来,我们一起来看看怎么用SOLIDWORKS中简单的操作来实现这两种智能的变更: 零件长度加长或缩短时,这排孔要按长度等距增减孔阵列的个数。 零件长度加长或缩短时,这排孔保持个数不变,按零件长度增减孔距。 那接下来,我们一起来看看怎么用简单的操作来实现这两种智能的

SOLIDWORKS艾金米 2076

背包问题入门 #3 | 多重背包问题的求解及其二进制优化

多重背包问题的求解及其二进制优化,适合初学者

陈涛的博客 2004

计算机视觉——SIFT特征匹配

文章目录一、SIFT特征检测原理1.1基本思想1.2二、SIFT特征检测图片兴趣点三、SIFT特征检测描述子匹配四、输入图片检测与之 一、SIFT特征检测原理 1.1基本思想 1.2 二、SIFT特征检测图片兴趣点 代码: 检测结果: 三、SIFT特征检测描述子匹配 四、输入图片检测与之 ...

weixin_43869874的博客 3853

多重背包问题(详解二进制优化原理)

推导二进制优化的过程并讲解二进制优化背后的底层原理,帮助你彻底掌握多重背包问题。

Turing_Sheep的博客 4738

华为2022硬件逻辑笔试题

单选题(每题两分) 1.以下关于过程赋值的描述,不正确的是() A在非阻塞性过程赋值中,使用赋值符号“< =” B赋值操作符是“=”的过程赋值是阻塞性过程赋值 C在非阻塞性过程赋值中,对目标的赋值是非阻塞的(因为时延),但可预定在将来某个时间步发生(根据时延:如果是0时延,那么在当前时间步结束) D非阻塞性过程赋值在其后所有语句执行前执行 解:D 2.芯片的功耗和下列哪种不强相关_____________。 A资源利用率 B核电压 C组合逻辑级数 D翻转率 解:A 3.下列说

weixin_44072819的博客 1万+

实战案例四:Claude Code + Excel 技能处理表格数据

Excel 是商业世界中最通用的数据工具。无论是财务报表、销售数据还是项目计划,Excel 无处不在。本案例将展示如何利用 Claude Code 的 Excel 技能,自动化处理复杂的表格数据,告别繁琐的手工操作。

gaoxiang_120的专栏 475

多重背包(二进制优化)

有N种物品和一个容量是V的背包。第i种物品最多有si​件,每件体积是vi​,价值是wi​。求解将哪些物品装入背包,可使物品体积总和不超过背包容量,且价值总和最大。输出最大价值。

初九·潜龙勿用的博客 2894

Android Framework AudioFlinge 面试题及参考答案

请解释什么是 AudioFlinger? AudioFlinger 是 Android 音频系统中的一个关键服务。它位于 Android 系统的中间层,是连接上层应用和底层音频硬件驱动的重要桥梁。从功能角度来讲,它主要负责音频数据的混合(Mix)以及输出(Output)。 当多个应用程序同时播放音频时,比如一个音乐播放器在播放歌曲,同时手机的闹铃响起,AudioFlinger 就会发挥它的混合功能。它会把这些不同来源的音频数据按照一定的规则和算法混合在一起。这种混合并不是简单的相加,而是要考

大模型大数据攻城狮的专栏 1573

POJ - 1742-Coins多重背包的可行性问题+二进制拆分优化

Coins 在这个背包模型里面,没有”物品价值“这个属性,不是最优解问题,而是可行性问题。 用多重背包的变形即可。 bool f[maxn]; f[0]=1; for(int i=1;i<=n;i++) for(int j=1;j<=c[i];j++) for(int k =m...

SongyangJi 512

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

poj 1742 Coins(二进制拆分+bitset优化多重背包)

\(Coins\) \(solution:\) 这道题很短,开门见山,很明显的告诉了读者这是一道多重背包。但是这道题的数据范围很不友好,它不允许我们直接将这一题当做01背包去做。于是我们得想一想优化。 $bitset $ 优化: 这个是我最先想到的,因为这道题只牵扯到了能不能买,就是一个“是”和“否”的问题,也就是说这个背包并没有什么权值(只有“可以”和“不可以”)然后就是单纯的状态转移。而...

weixin_30733003的博客 262

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

POJ 1742 Coins 混合背包(完全背包+多重背包二进制优化)

试题来源:做男人不容易系列:是男人就过8题——LouTiancheng题 本题给出nnn种硬币,设第iii种硬币的面值为AiA_iAi​,数量为CiC_iCi​,求这些硬币能够组成从1到m中的哪些数字? 对于第i种硬币,如果Ai∗Ci&gt;=mA_i*C_i&gt;=mAi​∗Ci​>=m,则可以把第iii种硬币的数量视为无穷,作为一个完全背包来求解;否则,就作为一个多重背...

侯山窝矿工 498

poj 1742 Coins(二进制优化多重背包)

传送门 解题思路   多重背包,二进制优化。就是把每个物品拆分成一堆连续的\(2\)的幂加起来的形式,然后把最后剩下的也当成一个元素。直接类似\(0/1\)背包的跑就行了,时间复杂度\(O(nmlogc)\)。 代码 #include<iostream> #include<cstdio> #include<cstring> #include<cmath&g...

weixin_30851409的博客 154

poj 1742 Coins 多重背包的可行性问题+优化讨论

是

weixin_43824564的博客 944

POJ--1742 Coins(DP,多重背包)

POJ–1742 Coins 给定N种硬币,其中第 i 种硬币的面值为Ai,共有Ci个。 从中选出若干个硬币,把面值相加,若结果为S,则称“面值S能被拼成”。 求1~M之间能被拼成的面值有多少个。 输入格式 输入包含多组测试用例。 每组测试用例第一行包含两个整数N和M。 第二行包含2N个整数,分别表示A1,A2,…,AN和C1,C2,…,CN。 当输入用例N=0,M=0时,表示输入终止,且该用例无...

qq_43148759的博客 342

POJ 1742 Coins

POJ 1742 Coins Description People in Silverland use coins.They have coins of value A1,A2,A3...An Silverland dollar.One day Tony opened his money-box and found there were some coins.He decided t...

anhaoti3785的博客 138

POJ - 1742 Coins(多重背包—二进制优化,背包可行性,单调队列优化)

多重背包习题POJ - 1742 题目大意:有n种不同价值的硬币,每种硬币对应一个数量,求它们能在价值为m的背包内拼凑出不同价值数量(1~m)。 这道题背包体积<=100000,最大的背包价值和数量(1<=Ai<=100000,1<=Ci<=1000),所以主要考虑时间复杂度 dp[i]背包容量为i时的最大价值 v[i]硬币的价值等同于体积 w[i]硬币的数量 1....

没有期待的日子反而会顺顺利利 416

poj1742 coins多重背包二进制优化+位运算

传送门 题意:给你几种硬币 以及 每种的个数 让你求能组合出几组m以内的数。 思路:多重背包模板,这里要转化成完全背包和01背包,同时使用位运算,因为只是判断个数,判断的是dp中的i是否存在,所以dp[i]设置成bool类型即可,同时使用位运算|判断能否组合。 #include <iostream> #include <cstring> #include <cstd...

weixin_43960370的博客 491

POJ 1742 Coins 多重背包(二进制优化/可行性分析)

优化: 当v[i] * num[i] >= weight时,该物品即可做完全背包处理 其他情况用二进制优化做01背包处理 #include <cstdio> #include <algorithm> #include <iostream> #include <string> #include <cstring> #incl...

xcatf的博客 376

蓝书(算法竞赛进阶指南)刷题记录——POJ1742 Coins(DP+贪心)

题目:POJ1742. 题目大意:给定nnn种物品,物品iii价值为AiA_iAi​,数量为CiC_iCi​,问1 m1~m1 m之间多少种面值能被凑出来. 1≤n≤100,1≤m,Ai≤105,1≤Ci≤1031\leq n\leq 100,1\leq m,A_i\leq 10^5,1\leq C_i\leq 10^31≤n≤100,1≤m,Ai​≤105,1≤Ci​≤103...

hzk_cpp的博客 304

【POJ1742】Coins

关于多重背包的一道题。 首先看数据便知道朴素的多重背包无法通过,所以我们采用二进制拆分进行优化,(二进制优化点这里),这样就能顺利通过本题了。 这道题只是判断可行性,所以“价值”这一状态并没有什么用。 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #i...

weixin_30886233的博客 129

【二进制拆分多重背包】POJ 1742 Coins

链接 http://poj.org/problem?id=1742 大意 给定nnn个物品,每个物品有CiCiC_i件,体积为AiAiA_i,给定一个容量为mmm的背包,问一共能组成多少种容量的方案? 思路 多重背包 但裸的背包会TLETLETLE,加下二进制优化2700ms2700ms2700ms卡卡过 当然也可以用单调队列优化 TLETLETLE代码 #inc...

Ajwallet 501

POJ1742 Coins 题解

博客园同步 原题链接 多重背包板子。具体可以参考 再谈单调队列优化 & 背包九讲. 这里再仔细讲一下二进制拆分的具体做法。 假设你有 777 个价值为 viv_ivi​,重量为 wiw_iwi​ 的物体。现在考虑把多重背包变成 010101 背包。如果我们把 111 个这样的物体看做第一组,222 个这样的物体看做第二组,444 个这样的物体看做第三组。你会发现用这三组进行的 010101 背包可以覆盖原来的情况(从二进制上很好理解),并且本来枚举 777 次,现在你不用去枚举这三组的所有情况(否则

bifanwen的博客 335
上一篇: HDU 1114 Piggy-Bank 【完全背包(时间优化)】
下一篇: POJ 2576 Tug of War 【二维01背包】
Y390d
博客等级 码龄9年 11粉丝 165原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值