hdu2844 & poj1742 Coin ---多重背包--两种方法

题意:你有N种硬币,每种价值A[i],每种数量C[i],问。在不超过M的情况下,我们用这些硬币,付款有多少种情况。也就是:1,2,3,4,5,....,M这么多种情况下,你能用你的硬币不找钱,付款多少种情况。

例如:

你有一种硬币,价值2,个数2,那么 你是不能付款 3元的。。你只能付款2,或者4元。。

OK,题意差不多就是这样啦。

那么这里有两种方式!

分析:

那么这里我们可以用多重背包来解决,我们把价值和重量看成一样的w[i] = A[i];用M作为背包。那么dp 过后,我们就可以知道 dp[i] 表示的含义为,不超过i元钱的情况下,用拥有的硬币能构成的最大钱数。那么很明显,如果dp[i] = i,意思就是 用拥有的钱,可以刚好构成 i 元钱,上马:

//281MS 648K
#include <stdio.h>
#include <string.h>

#define MAX 102

int ans;//最后答案
int n,m;
int A[MAX],C[MAX];
int dp[100005];

void ZeroOne(int V,int W)
{
    for(int i = m; i >= V; i--)
        //dp[i] = dp[i]>dp[i-V]+W ? dp[i]:dp[i-V]+W;
        if(dp[i]<dp[i-V]+W)
        {
            dp[i] = dp[i-V]+W;//这里需修改如此统计
            if(dp[i] == i) ans ++;//在dp过程中,会有出现dp[j]更新为j的时候 且只有一次,也要放在dp[i]=dp[i-V]+W;此语句后
        }
}

int main()
{
    while(scanf("%d%d",&n,&m),n+m)
    {
        ans = 0;
        memset(dp,0,sizeof(dp));
        for(int i = 1; i <= n; i ++) scanf("%d",&A[i]);
        for(int i = 1; i <= n; i ++) scanf("%d",&C[i]);

        for(int i = 1; i <= n; i ++)
        {
            if(A[i]*C[i] >= m)
            {
                for(int j = A[i]; j <= m; j ++)
                    //dp[j] = dp[j]>dp[j-A[i]]+A[i] ? dp[j]:dp[j-A[i]]+A[i]; //将价值和重量看做相同
                    if(dp[j]<dp[j-A[i]]+A[i]) //这里需修改如此统计ans
                    {
                        dp[j] = dp[j-A[i]]+A[i];
                        if(dp[j] == j) ans ++; //在dp过程中,会有出现dp[j]更新为j的时候 且只有一次,也要放在dp[i]=dp[i-V]+W;此语句后
                    }
            }
            else
            {
                int k = 1;
                while(k <= C[i])
                {
                    ZeroOne(A[i]*k,A[i]*k);
                    C[i] -= k;
                    k *= 2;
                }
                ZeroOne(C[i]*A[i],C[i]*A[i]);
            }
        }
        //for(int i = 1; i <= m; i ++) if(dp[i]==i)ans++;//这里用以用在hdu,但是poj需要用上面的方式统计ans,不然会超时,过了也过得很险 2654ms........汗。。。。。
        printf("%d\n",ans);
    }
    return 0;
}

那么这里还有一种方式

用flag[i]表示能不能构成 钱为 i 的情况

time[j] 表示,构成 j 元钱的时候,用第 i 种硬币的个数

#include <iostream>
#include <cstring>
using namespace std;

#define MAX 100005

int N,M;
int A[MAX],C[MAX];
bool flag[MAX];
int time[MAX];

int main()
{
    while(cin >> N >> M)
    {
        if(!N && !M)break;
        for(int i = 0; i < N; i ++) cin >> A[i];
        for(int i = 0; i < N; i ++) cin >> C[i];

        int ans = 0;
        memset(flag,false,sizeof(flag));
        flag[0] = true;
        for(int i = 0; i < N; i ++){
            memset(time,0,sizeof(time));
            for(int j = A[i]; j <= M; j ++){//这里解释为,只有当前j这种情况没有构成,并且j-A[i]的情况存在--(这里也就是类似完全背包,这次状态应该依赖前面存在情况),同时到j为止,用第i种硬币的数量不超过C[i]的情况下才满足条件
                if(!flag[j] && flag[j-A[i]] && time[j-A[i]]+1 <= C[i]){
                    flag[j] = true;
                    time[j] = time[j-A[i]]+1;
                    ans ++;
                }
            }
        }
        cout << ans <<endl;
    }
    return 0;
}

个人愚昧观点,欢迎指正与讨论

hdu2844 & poj1742 Coin ---多重背包--两种方法

时间: 2024-08-02 19:57:36

hdu2844 & poj1742 Coin ---多重背包--两种方法的相关文章

一、查看Linux内核版本命令(两种方法):

一.查看Linux内核版本命令(两种方法): 1.cat /proc/version [[email protected]CentOS home]# cat /proc/versionLinux version 2.6.32-431.el6.x86_64 ([email protected]) (gcc version 4.4.7 20120313 (Red Hat 4.4.7-4) (GCC) ) #1 SMP Fri Nov 22 03:15:09 UTC 2013 2.uname -a [

利用颜色和形态学两种方法进行车牌区域提取的OpenCV代码

要想提取车牌号,首先你要定位车牌区域嘛,本文分别两种方法用,即颜色和形态学的方法,对车牌区域进行判定.说得是两种方法,其实两种方法并无多大的区别,只是有一步的判断标准不一样而已,你看了下面整理出的的思路就知道两者的区别真的很小了. 方法一:利用颜色提取车牌区域的思路: ①求得原图像的sobel边缘sobelMat ②在HSV空间内利用车牌颜色阈值对图像进行二值化处理,得到图像bw_blue→ ③由下面的判别标准得到图像bw_blue_edge for (int k = 1; k != heigh

ios图片拉伸两种方法

ios图片拉伸两种方法 UIImage *image = [UIImage imageNamed:@"qq"]; 第一种: // 左端盖宽度 NSInteger leftCapWidth = image.size.width * 0.5f; // 顶端盖高度 NSInteger topCapHeight = image.size.height * 0.5f; // 重新赋值 image = [image stretchableImageWithLeftCapWidth:leftCapW

Android第五期 - 更新自己的apk本地与网络两种方法

首先是本地: ParseXmlService部分: package com.szy.update; import java.io.InputStream; import java.util.HashMap; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.w3c.dom.Document; import org.w3c.dom.Element

Linux中生成密钥的两种方法

Linux中生成密钥的两种方法 SSH服务支持一种安全认证机制,即密钥认证.所谓的密钥认证,实际上是使用一对加密字符串,一个称为公钥(publickey), 任何人都可以看到其内容,用于加密:另一个称为密钥(privatekey),只有拥有者才能看到,用于解密.通过公钥加密过的密文使用密钥可以轻松解密,但根据公钥来猜测密钥却十分困难. ssh的密钥认证就是使用了这一特性.服务器和客户端都各自拥有自己的公钥和密钥.如何使用密钥认证登录linux服务器呢? 在使用密钥认证远程登入linux之前,我们

pdf文件怎么修改 修改PDF文件的两种方法

都说PDF格式的文件不能修改,我就呵呵了!不管你们信不信,反正我是不信.因为我会修改PDF文件,并且方法还不止一种.想知道我是怎么修改PDF文件的吗?下面我就告诉大家修改PDF文件的两种方法. 方法一 1.方法一就是将PDF文件转换成一种可容易编辑的文档,如:word.excel.ppt等格式,然后再进行编辑,编辑好后再将其转换成PDF格式,是不是很简单!具体是该如何转换的,下面有详细教程. 2.下载一个PDF转换器,并将它安装在电脑上.工具最好是支持双向转换的那种,如:http://www.x

zabbix使用自己编写脚本模板和zabbix自带模板两种方法添加对指定进程和端口的监控

zabbix使用自己编写脚本模板和zabbix自带模板两种方法添加对指定进程和端口的监控 1.自带监控模板进行os的监控 进入/usr/local/zabbix/etc/zabbix_agentd.conf 配置文件修改 LogRemoteCommands=1     ###开启脚本功能 Server=192.168.5.129     ##修改zabbix指向的服务器: 重启zabbix_agentd.zabbix_server服务 在配置-->主机-->添加主机--> 配置主机信息主

快速生成较大文本文档的两种方法

在学习用FTP发送文件的过程中,需要用到一个比较大的文件进行传输测试.因此百度了一下如何生成指定大小文件的方法,发现在WINDOWS下有两种方法比较实用,记录如下: 第一种方法: 在运行窗口中输入CMD命令回车,进入命令行模式. 在此界面下输入:"fsutil file creatnew test.txt 1024"即可产生一个占用空间为1024字节,名为test.txt的文本. 命令中1024即为该文件占用空间大小,可以任意指定.比如输入1048576就可以产生一个1M大小的文件.当

实现icon和文字垂直居中的两种方法-(vertical-align and line-height)

方法一:vertical-align 在w3school定义:该属性定义行内元素的基线相对于该元素所在行的基线的垂直对齐 百思不得骑姐 然后Google,反正在w3schools上面并没有找到定义 仅仅能写代码測试 而后个人理解,才作出如此解释> 该属性作用的对象:行内元素(inline,inline-block也有行内属性) 其它table-cell 经常使用属性值:top middle bottom 个人理解 个人觉得,普通情况下,这些字母自发"坐落"的这条线就是基线.然后两