楼教主男人必解八题之 Coins 解题报告

2023-05-16


 
 
楼教主男人必解八题之 Coins 解题报告
题目详见http://acm.hdu.edu.cn/showproblem.php?pid=2844 这个题目和POJ1742是一个题目,也是楼教主的男人八题之一。 说的是给出N种硬币的价值和个数,问可以取到1---M中的多少个值。这个很显然是和背包问题是一样的,略有一点点区别。 解题思路:就是把M当成背包体积总和,硬币的价值也是组成M的一部分,也是看成体积,当然他也是价值,也即是双重身份。这个理所当然用多重背包来解答。而且要划分类剪枝,因为对于满足价值*数量大于等于给定最大价值的硬币就用完全背包来解答,对于满足个数为1的硬币就用01背包来解答。而且我们最后要求的不是最大的那个值 而是满足p[i]==i的那个,说明这个i价值可以达到。 OK,上代码

#include <iostream>   
using namespace std;    
int main()
{
    int N,M;
    int i,j,k;
    int *p,*num,*value;
    int number;
    while(cin>>N>>M)
    {
        if(N==0&&M==0)
            break;
        number=0;
        num=new int[N+1];
        value=new int[N+1];
        for(i=1;i<=N;i++)
            cin>>value[i];
        for(i=1;i<=N;i++)
            cin>>num[i];
        p=new int[M+1];
        for(i=0;i<=M;i++)
            p[i]=0;
        for(i=1;i<=N;i++)
        { 
            for(k=1;k<=num[i];k++)
                for(j=M;j>=value[i];j--)   
                {
                    if(p[j-value[i]]+value[i]>p[j])
                        p[j]=p[j-value[i]]+value[i];
                    else
                        p[j]=p[j];
                }
        }
        for(i=1;i<=M;i++)
            if(p[i]==i)
                number++;
            cout<<number<<endl;
    }
    return 0;
}


	提交到HDOJ是TLE,换到HDOJ也是一样。说明时间复杂度还真是高,无奈我又继续想,划分的时候用二进制优化拆分 不懂的可以看这里背包问题  

#include<iostream>   
using namespace std;    
int main()
{
    int N,M;
    int i,j,k;
    int *p,*num,*value;
    int number;
    while(cin>>N>>M)
    {
        if(N==0&&M==0)
            break;
        number=0;
        num=new int[N+1];
        value=new int[N+1];
        for(i=1;i<=N;i++)
            cin>>value[i];
        for(i=1;i<=N;i++)
            cin>>num[i];
        p=new int[M+1];
        for(i=0;i<=M;i++)
            p[i]=0;
        for(i=1;i<=N;i++)
        { 
            for(k=1;k<num[i]+1;k*=2)
            {
                if(2*k>num[i]+1)
                {
                    k=num[i]+1-k; //最后一个拆分值
                    for(j=M;j>=k*value[i];j--)   
                    {
                        if(p[j-k*value[i]]+k*value[i]>p[j])
                            p[j]=p[j-k*value[i]]+k*value[i];
                        else
                            p[j]=p[j];
                    }
                    break;
                }
                else
                {
                    for(j=M;j>=k*value[i];j--)   
                    {
                        if(p[j-k*value[i]]+k*value[i]>p[j])
                            p[j]=p[j-k*value[i]]+k*value[i];
                        else
                            p[j]=p[j];
                    }
                }
            }
        }
        for(i=1;i<=M;i++)
            if(p[i]==i)
                number++;
        cout<<number<<endl;
    }
    return 0;
}

	继续提交代码 TLE,真心无力感。。想了好久无奈的很啊,人家的都AC了,为毛我这里要TLE,代码没什么大的差别啊。(以后千万不敢说没啥差别了)
	然后我想到多重可以包含01和完全,可以剪枝。  
#include <iostream>   
using namespace std;    
int main()
{
    int N,M;
    int i,j,k;
    int *p,*num,*value;
    int number;
    while(cin>>N>>M)
    {
        if(N==0&&M==0)
            break;
        number=0;
        num=new int[N+1];
        value=new int[N+1];
        for(i=1;i<=N;i++)
            cin>>value[i];
        for(i=1;i<=N;i++)
            cin>>num[i];
        p=new int[M+1];
        for(i=0;i<=M;i++)
            p[i]=0;
        for(i=1;i<=N;i++)
        { 
            if(num[i]==1)
            {
                for(j=M;j>=value[i];j--)   
                {                                    
                    if(p[j-value[i]]+value[i]>p[j])
                        p[j]=p[j-value[i]]+value[i];
                    else
                        p[j]=p[j];                
                }
            }
            else if(num[i]*value[i]>M)
            {
                for(j=0;(j<=M)&&(value[i]<=j);j++)   
                {
                    if(p[j-value[i]]+value[i]>p[j])
                        p[j]=p[j-value[i]]+value[i];
                    else
                        p[j]=p[j];
                }
            }
            else
            {
                for(j=M;j>=value[i];j--)   
                {    
                    for(k=0;k<=num[i];k++)
                    {
                        if((j>=k*value[i])&&(p[j-k*value[i]]+k*value[i]>p[j]))
                            p[j]=p[j-k*value[i]]+k*value[i];
                        else
                            p[j]=p[j];
                    }
                }
            }
        }
        for(i=1;i<=M;i++)
            if(p[i]==i)
                number++;
            cout<<number<<endl;
    }
    return 0;
}
改进之后继续提交还是AC不了。对于这个多重背包这算是很优的算法了啊。最后我觉得可能是求的时候重复量太多了?
改变一下状态转换方程:p[i][j]=p[i][j-value[i]]+1;p[i][j]的意思是前i个硬币可以组成价值j吗?初始化是0(不能),如果前i个硬币可以组成价值j,再加1。而p[i][j-value[i]]的意思就是前i个硬币可以组成价值j-value[i]吗?如果可以组成,则说明第i个硬币再加入就可以组成价值j了。当然前提是p[i][j-value[i]]要小于num[i],因为如果等于num[i],说明前i个硬币能组成价值j-value[i]的时候硬币已经用完了,没了,不能再组成其他价值了。
可是对于最后的1-M价值的个数怎么求?判断一下是p[i][j]是否为0,对于每一行也就是说对于每一个i,0--M中只要有一个p[i][j]>0,就说明可以组成价值j,这样统计加一起就可以了。

#include<iostream>   
using namespace std;    
int main()
{
    int N,M;
    int i,j;
    int p[105][100005];
    int num[105],value[105];
    int number;
    while(cin>>N>>M)
    {
        if(N==0&&M==0)
            break;
        number=0;
        for(i=1;i<=N;i++)
            cin>>value[i];
        for(i=1;i<=N;i++)
            cin>>num[i];
        for(i=1;i<=N;i++)
            for(j=1;j<=M;j++)
                p[i][j]=0;
        for(i=1;i<=N;i++)
        { 
            for(j=value[i];j<=M;j++)   
            {
                if(p[i][j-value[i]]&&(p[i][j-value[i]]<num[i]))
                {
                    p[i][j]=p[i][j-value[i]]+1;
                }
            }
            
        }
        for(i=1;i<=N;i++)
        {
            for(j=1;j<=M;j++)
            {
                if(p[i][j])
                {
                    number++;
                    break;
                }
            }
        }
        cout<<number<<endl;
    }
    return 0;
}


	提交代码 栈溢出。。。。
	OJ测试的时候二维是数组是p[100][100000],当然有问题了。不过我想起来01背包的优化,这个也许可以变成一维数组。  

	状态转换方程p[j]=p[j-value[i]]+1;不过呢?对于每一种的硬币组成的价值是相互冲突的,也就是说是第i-2种硬币可以组成的价值j被当成了第i种可以组成j价值的值。这咋办,而且对于求最后的number也是问题。所以我觉得对于每一种硬币都初始化数组,这样就可以了。可是求number不好求了,不要紧的,在循环里面每求出一个我们就++。不过我们可以还要定义一个flag[i]数组,对于每求出一个值我们就不再求了。求组成价值j个时候要判断j-value[i]价值的组成是否已求出,否则不可以求,这和刚才代码的判断是一个意思。  

#include<iostream>   
using namespace std;    
int main()
{
    int N,M;
    int i,j,k;
    int *p,*num,*value;
	bool *flag;
	int number;
    while(cin>>N>>M)
    {
        if(N==0&&M==0)
			break;
		number=0;
		value=new int[N+1];
		num=new int[N+1];
        for(i=1;i<=N;i++)
            cin>>value[i];
        for(i=1;i<=N;i++)
            cin>>num[i];
		flag=new bool[M+1];
		p=new int[M+1];
		for(i=1;i<=M;i++)
            flag[i]=false;
		flag[0]=true;
        for(i=1;i<=N;i++)
        { 
			for(k=0;k<=M;k++)
				p[k]=0;
			for(j=value[i];j<=M;j++)   
			{
				if(!flag[j]&&flag[j-value[i]]&&(p[j-value[i]]<num[i]))
				{
					p[j]=p[j-value[i]]+1;
					flag[j]=true;
					number++;
				}
				else
					p[j]=p[j];
			}
			
        }
		cout<<number<<endl;
    }
    return 0;
}


	这次提交上去之后发现还是没有AC,HDOJ说是WA,POJ说是MLE。我真心无力了,无力吐槽。这一次我终于发现我和别人代码的不同了,我用的是指针指向的动态内存,看起来是节省内存了(?)。别人用的是静态内存,就是定义一个满足最大值的数组。我想,试试吧。  

#include<iostream>   
using namespace std;    
int main()
{
    int N,M;
    int i,j,k;
    int p[100005],num[105],value[105];
    bool flag[100005];
    int number;
    while(cin>>N>>M)
    {
        if(N==0&&M==0)
            break;
        number=0;
        for(i=1;i<=N;i++)
            cin>>value[i];
        for(i=1;i<=N;i++)
            cin>>num[i];
        for(i=1;i<=M;i++)
            flag[i]=false;
        flag[0]=true;
        for(i=1;i<=N;i++)
        { 
            for(k=0;k<=M;k++)
                p[k]=0;
            for(j=value[i];j<=M;j++)   
            {
                if(!flag[j]&&flag[j-value[i]]&&(p[j-value[i]]<num[i]))
                {
                    p[j]=p[j-value[i]]+1;
                    flag[j]=true;
                    number++;}

            }
            
        }
        cout<<number<<endl;
    }
    return 0;
}


	果真AC了,苍天啊,难道就是这一点差别吗?然后我不甘心的把二进制划分的代码也改成定义的超大数组,又AC了。我又把多重的一般做法提交,没有AC。看来二进制的划分优化是有作用的。难道就是仅仅几个指针的区别吗?没办法,以后提交代码的时候就定义超大数组吧。但是自己写代码的时候可不能这样,还是以节省内存为主啊。
	不过楼教主还提到一个算法,就是单调递增序列的问题,这个我目前还在搞懂中。。有人会请给我讲讲。  

	转载请注明出处http://blog.csdn.net/liangbopirates/article/details/9750723  

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

楼教主男人必解八题之 Coins 解题报告 的相关文章

  • HDOJ 1058 Humble Numbers解题报告【DP】

    Humble Numbers 题目详见http acm hdu edu cn showproblem php pid 61 1058 开始拿到这个题目的时候还纠结了半天 xff0c 英语很差的话这个题是不可能AC的 而我就是其中之一 Hum
  • 楼教主男人必解八题之 Coins 解题报告

    楼教主男人必解八题之 Coins 解题报告 题目详见http acm hdu edu cn showproblem php pid 61 2844 这个题目和POJ1742是一个题目 xff0c 也是楼教主的男人八题之一 说的是给出N种硬币
  • [转载]最小矩形(rec1)的解题报告

    百度之星2009大赛的第二场有一道和此相关的题目 xff0c 如果看透这篇文章应该好写了 xff0c 不过可惜我事后才看到 xff0c 郁闷啊 xff01 xff01 还是要多看看书 原文 xff1a http www pmit com c
  • Leetcode Decode Ways 解题报告

    A message containing letters from A Z is being encoded to numbers using the following mapping 39 A 39 gt 1 39 B 39 gt 2
  • zoj3961解题报告

    借今年浙江省赛的题练练手 首先 xff0c 由题意知 xff0c A与B发信息 xff0c 当A与B连续互相发信息m天时 xff0c 好感度point 43 1 输入有A向B发信息的天数与B向A发信息的起止天数 xff0c 具体格式看题 n
  • UVA10881解题报告

    还是那句话 xff0c 解题先看题 由题意知有一根长度为L的木棒 xff0c 木棒上面有n只蚂蚁 xff0c 每只蚂蚁或朝左或朝右且以每秒1cm的速度移动 xff0c 吗 xff0c 蚂蚁相撞后掉头 xff0c 问T秒后每只蚂蚁的状态 xf
  • UVA1592解题报告

    这道题让我费了我好几天的时间 xff0c 差不多打掉了我对算法的全部信心 不过 xff0c 幸好 xff0c 经过几天的努力我终于AC了这道题 xff0c 解开了我的一个大心结 下面我将列出三份代码 xff0c 其中后两份是WA代码用来给同
  • UVA1594解题报告

    这么垃圾的代码竟然没有超时 xff0c 我真不知道是该欢喜还是愁 AC代码 Time 0 11s include lt cstdio gt include lt cmath gt using namespace std const int
  • uva12100解题报告

    水题留念 一个队列模拟进出操作 xff0c 一个优先队列保存优先级 xff0c 模拟过程输出结果 Time 0ms include lt cstdio gt include lt queue gt include lt cstring gt
  • UVA232解题报告

    注意一个地方 xff0c 编号是从左到右 从上往下增大的 xff0c 所以我们可以从这里做文章按照编号大小的顺序遍历输出 实际上 xff0c 因为给出的数据范围很小我们的求解速度还是很快的 xff0c 尤其是横向输出时还可以做点小手脚加快运
  • UVA230解题报告

    这个题耗了我六天时间 xff0c 很打击我对算法的学习 xff0c 不过 xff0c 我终于解决了他 分析如下 仔细观察我们可以发现后面的操作与输出都是围绕标题 xff08 title xff09 展开的 xff0c 作者 xff08 au
  • UVA10562解题报告

    我的GitHub地址 xff1a https github com DongChengrong ACM Program 仔细观察他给出的树 xff0c 我们可以发现这棵多叉树长得比较有特点 最上是树根 xff0c 而每一个节点只要有孩子下面
  • UVA227解题报告

    因为网格中存在空格所以用gets录入 xff0c 首先录入一行数据 xff0c 如果第一个字符为 39 Z 39 则break退出循环 其次是对指令的接受与处理 接受指令可以用getchar xff0c 遇到换行符跳过 处理也很简单 xff
  • HDU - 3018解题报告

    题意简述 给出n个节点 xff0c m条边 xff0c 问要想全部经过这m条边且每个边只经过一次至少需要多少条路径 分析 这个题实际上就是一笔画问题中的定理二 xff1a 如果连通无向图 G 有 2k 个奇顶点 xff0c 那么它可以用 k
  • 迷宫问题(2) 解题报告

    迷宫问题 问题描述 给定一个N M方格的迷宫 xff0c 迷宫里有T处障碍 xff0c 障碍处不可通过 给定起点坐标和终点坐标 xff0c 问每个方格最多经过1次 xff0c 有多少种从起点坐标到终点坐标的方案 在迷宫中移动有上下左右四种方
  • HDOJ 1058 Humble Numbers解题报告【DP】

    Humble Numbers 题目详见http acm hdu edu cn showproblem php pid 61 1058 开始拿到这个题目的时候还纠结了半天 xff0c 英语很差的话这个题是不可能AC的 而我就是其中之一 Hum
  • 楼教主男人必解八题之 Coins 解题报告

    楼教主男人必解八题之 Coins 解题报告 题目详见http acm hdu edu cn showproblem php pid 61 2844 这个题目和POJ1742是一个题目 xff0c 也是楼教主的男人八题之一 说的是给出N种硬币
  • Print in Order 解题报告(C++)

    我们提供了一个类 xff1a public class Foo public void one print 34 one 34 public void two print 34 two 34 public void three print
  • Can you solve this equation?(二分)

    Problem Description Now given the equation 8 x 4 7 x 3 2 x 2 3 x 6 Y can you find its solution between 0 and 100 Now ple
  • 蓝桥杯 砝码称重 递归 解题报告

    5个砝码 用天平称重时 我们希望用尽可能少的砝码组合称出尽可能多的重量 如果只有5个砝码 重量分别是1 3 9 27 81 则它们可以组合称出1到121之间任意整数重量 砝码允许放在左右两个盘中 本题目要求编程实现 对用户给定的重量 给出砝

随机推荐

  • python3中替换python2中cmp函数的新函数分析(lt、le、eq、ne、ge、gt)

    本文地址 xff1a http blog csdn net sushengmiyan article details 11332589 作者 xff1a sushengmiyan 在python2中我们经常会使用cmp函数来比较一些东西 x
  • Eclipse中查看没有源码的Class文件的方法

    本文地址 http blog csdn net sushengmiyan article details 18798473 本文作者 sushengmiyan 我们在使用Eclipse的时候 xff0c 经常是会使用别人的Jar包 xff0
  • [ExtJS5学习笔记]第二节 Sencha Cmd 学习笔记 使你的sencha cmd跑起来

    本文地址 xff1a http blog csdn net sushengmiyan article details 38313537 本文作者 xff1a sushengmiyan 资源链接 翻译来源 Sencha Cmd官方网站 xff
  • 【Java二十周年】Delphi转行java的一些小感触

    本文纯属一届小码农对java使用过程的体验感触 目录 xff1a 初遇java编程语言与java的擦肩深入java 跨平台性开源支持web的支撑 初遇java编程语言 刚上大学的时候 xff0c 完全是个电脑盲 刚入学学的计算机普及知识就是
  • Vmware-虚拟中的linux如何增加硬盘(转)

    启动虚拟机软件VMware后 xff0c 点机VM菜单选择Setting xff0c 然后在弹出地菜单中选择 xff1a Add命令进行添加硬盘操作 完成后启动虚拟机 1 建立分区 fdisk l查看磁盘分区情况 此时你会发现多了一个 de
  • 给大家安利一个学习angular2的视频网站

    本文地址 xff1a http blog csdn net sushengmiyan 本文作者 xff1a 苏生米沿 视频地址 xff1a https egghead io courses angular 2 fundamentals 网站
  • 记一个万金油开源框架JHipster

    本文地址 xff1a http blog csdn net sushengmiyan article details 53190236 百搭代码生成框架 体验新技术汇总 xff1a Spring BootSpring SecurityAng
  • SQLServer触发器创建、删除、修改、查看...适用于级联删除

    一 触发器是一种特殊的存储过程 它不能被显式地调用 而是在往表中插入记录 更新记录或者删除记录时被自动地激活 所以触发器可以用来实现对表实施复杂的完整性约束 二 SQL Server为每个触发器都创建了两个专用表 Inserted表和Del
  • 工薪族巧理财之定期存款中整存整取、零存整取、存本取息之间的微妙区别

    银行的官方术语先给大家普及一下 xff1a 定期存款是在存款时约定存储时间 一次或按期分次 在约定存期 存入本金 xff0c 整笔或分期平均支取本金利息的一种储蓄 按存取方式定期存款分为整存整取定期存款 零存整取定期存款 存本取息定期存款
  • no module named win32com.client错误解决

    无论什么时候 xff0c 你在运行的时候发现有importError no module named win32com client这个提示 你都可以这么解决 xff1a 请下载http sourceforge net projects p
  • java.util.concurrent同步框架(AQS论文中文翻译)

    java util concurrent同步框架 摘要目录和主题描述一般条款关键字1 介绍 xff1a 需求设计实现4 使用方式5 性能6 结论7 致谢 Doug Lea SUNY Oswego Oswego NY 13126 dl 64
  • POJ2287 田忌赛马---贪心算法

    田忌赛马 题目详见http poj org problem id 61 2287 田忌赛马大家都听过 xff0c 可是如果不是上中下三等马 xff0c 而是很多匹马 xff0c 优劣有很多种分类 xff0c 就不仅仅是321的问题了 这个很
  • 贪心算法详解

    之前讲过动态规划DP xff0c 现在来说说贪心 贪心算法在解决问题的策略上目光短浅 xff0c 只根据当前已有的信息就做出选择 xff0c 而且一旦做出了选择 xff0c 不管将来有什么结果 xff0c 这个选择都不会改变 也就是说贪心对
  • 搜索智能提示suggestion,附近点搜索

    第三十六 三十七章 搜索智能提示suggestion xff0c 附近地点搜索 作者 xff1a July 致谢 xff1a caopengcs 胡果果 时间 xff1a 二零一三年九月七日 题记 写博的近三年 xff0c 整理了太多太多的
  • 多重继承及虚继承中对象内存的分布

    多重继承及虚继承中对象内存的分布 这篇文章主要讲解G 43 43 编译器中虚继承的对象内存分布问题 xff0c 从中也引出了dynamic cast和static cast本质区别 虚函数表的格式等一些大部分C 43 43 程序员都似是而非
  • Linux日志服务器配置

    配置日志服务器 环境 xff1a tibet xff1a 10 11 3 57 gaplinux xff08 日志服务器 xff09 xff1a 10 11 3 3 修改tibet上的 etc hosts xff0c 增加如下代码 xff1
  • 【Google】25匹马的角逐

    问题是这样的 xff1a 一共有25匹马 xff0c 有一个赛场 xff0c 赛场有5个赛道 xff0c 就是说最多同时可以有5匹马一起比赛 假设每匹马都跑的很稳定 xff0c 不用任何其他工具 xff0c 只通过马与马之间的比赛 xff0
  • HDOJ 1058 Humble Numbers解题报告【DP】

    Humble Numbers 题目详见http acm hdu edu cn showproblem php pid 61 1058 开始拿到这个题目的时候还纠结了半天 xff0c 英语很差的话这个题是不可能AC的 而我就是其中之一 Hum
  • 背包问题详解

    背包问题 背包问题 Knapsack problem 是一种组合优化的NP完全问题 问题可以描述为 xff1a 给定一组物品 xff0c 每种物品都有自己的体积和价值 xff0c 在限定的总体积内 xff0c 我们如何选择 xff0c 才能
  • 楼教主男人必解八题之 Coins 解题报告

    楼教主男人必解八题之 Coins 解题报告 题目详见http acm hdu edu cn showproblem php pid 61 2844 这个题目和POJ1742是一个题目 xff0c 也是楼教主的男人八题之一 说的是给出N种硬币