HDOJ 1058 Humble Numbers解题报告【DP】

2023-10-26

 
 
Humble Numbers
题目详见http://acm.hdu.edu.cn/showproblem.php?pid=1058
	开始拿到这个题目的时候还纠结了半天,英语很差的话这个题是不可能AC的。。而我就是其中之一。。。
	Humber Number不用管它啥意思,就是一类定义的数而已。如果一个数的质因数(素因数)仅仅是2、3、5 or 7的话那就被称为Humber Number。特殊的1也在其列。而且题目给出了前20个Humber Number。1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 15, 16, 18, 20, 21, 24, 25, 27。注意仅仅二字,11包含质因数11,26包含质因数13都不在其列。编写程序求第n个Humble Number。输入输出格式要搞明白。
	OK,搞清了题意,那就来分析一下。这个题的意思很清楚明了,就是给你一个N,求出第N个Humble Number。如何求?一开始我想到遍历,可是觉得很麻烦,估计会很超时。我就想啊,既然是2 3 5 7 ,我用1和他们相加如何?得到了3 4 6 8,这些数肯定是Humble Number。可是如何继续下去呢?用3和2 3 5 7相加?得到 5 6 8 10,还要用4和他们相加?继续下去?感觉很繁琐,就像是一颗树4叉树一样。  
	所以我放弃了这个思路,又开始想遍历,如果我知道了某个数是不是Humble Number,那我不就可以统计第N个了吗?从1开始遍历,如果i是Humble Number,那我就nums++,知道nums和你给定的N相等我们就求出了。。如何判断一个数是不是Humble Number呢?Humble Number的质因数只能是2 3 5 7 ,被这些数分别整除后结果肯定是1,而且整除次数最多是Number/2.
OK,上代码

#include <iostream>   
using namespace std;

//查看n是不是Humble Number
int IsHumbleNumber(long int n);
    
int main()
{	
	long int nums;
	long int number;
	long int i;
	while(cin>>number)
	{
		if(0==number)
			break;
		nums=0; //初始化  记录有多少个HumbleNumber 
		for(i=1;;i++)
		{
			if(IsHumbleNumber(i))
				nums++;
			if(number==nums)
				break;
		} //此时i的值就是第number个humble number
		//输出格式
		if((number>=4)&&(number<=20))
			cout<<"The "<<number<<"th humble number is "<<i<<endl; //英语差了这个题别想AC了。。。
		else if(1==(number-(number/10)*10))
			cout<<"The "<<number<<"st humble number is "<<i<<endl;
		else if(2==(number-(number/10)*10))
			cout<<"The "<<number<<"nd humble number is "<<i<<endl;
		else if(3==(number-(number/10)*10))
			cout<<"The "<<number<<"rd humble number is "<<i<<endl;
		else
			cout<<"The "<<number<<"th humble number is "<<i<<endl; 
	}
	return 0;
}


//查看n是不是Humble Number
int IsHumbleNumber(long int n)
{
	//long int num=1; 
	if(n==1)  //1 is Humble Number
		return true;
	long int num=n;
	long int i;
	for(i=1;i<=num/2;i++)
	{
		if(n%2==0)
			n/=2;
		else if(n%3==0)
			n/=3;
		else if(n%5==0)
			n/=5;
		else if(n%7==0)
			n/=7;
	}
	if(n==1)
		return true;
	else
		return false;
}

	提交之后发现超时,时间复杂度是Humber(N),这个N如果是5842,那么Humber(N)=20亿,超时是必然的结果。而且每次给定的N,都要从头来过。这让我想到了数组,用一个数组把所有的全部存起来,会不会好一些呢?
代码
#include <iostream>   
using namespace std;

//查看n是不是Humble Number
int IsHumbleNumber(int n);
int main()
{	
	int nums;
	int number;
	long int i;
	int j;
	long int humble[5843]={0};//0位不用
	for(j=1;j<=5842;j++)
	{
		for(i=humble[j-1]+1;;i++)
		{
			if(IsHumbleNumber(i))
				break;
		} 
		humble[j]=i;//此时i的值就是第j个humble number
	}
	while(cin>>number)
	{
		if(0==number)
			break;

		//输出格式
		if((number>=4)&&(number<=20))
			cout<<"The "<<number<<"th humble number is "<<humble[number]<<endl; //英语差了这个题别想AC了。。。
		else if(1==(number-(number/10)*10))
			cout<<"The "<<number<<"st humble number is "<<humble[number]<<endl;
		else if(2==(number-(number/10)*10))
			cout<<"The "<<number<<"nd humble number is "<<humble[number]<<endl;
		else if(3==(number-(number/10)*10))
			cout<<"The "<<number<<"rd humble number is "<<humble[number]<<endl;
		else
			cout<<"The "<<number<<"th humble number is "<<humble[number]<<endl; 
	}
	return 0;
}


//查看n是不是Humble Number
int IsHumbleNumber(int n)
{
	//long int num=1; 
	if(n==1)  //1 is Humble Number
		return true;
	int num=n;
	int i;
	for(i=1;i<=num/2;i++)
	{
		if(n%2==0)
			n/=2;
		else if(n%3==0)
			n/=3;
		else if(n%5==0)
			n/=5;
		else if(n%7==0)
			n/=7;
	}
	if(n==1)
		return true;
	else
		return false;
}
	NO,还是超时!因为整个求Humber Number的过程是Humber(5842),也就是20亿,肯定会超时啦。。。所以来说,这个是行不通的。前100个还是很好求的,后面就不行了。
	逼不得已放弃这个思路。看这个20亿,我觉得时间复杂度可不可以是和N相关的和Humber Number没关系,O(N)?可以不?
	想一想开始时候的想法,4叉树,必然有很多相同的节点,那么这就是重叠子问题?而且求第N个Humber Number是和第N-1个Humber Number有关系的?也就是说问题的最优解可以用子问题的最优解来解决,这不是传说中的DP吗?
	OK,有点兴奋,怎么做?如何得到表达式?用第一次的思路,用加不行,可以用乘吗?1*2,1*3,1*5,1*7?得出的结果怎么办?所有的数还要和 2 3  5 7相乘,这不是和用加是一样的吗?绞尽脑汁,终于发现了一点规律了,一开始用1相乘的结果中最小值的就是2,这就是第2个Humber Number。然后呢?如果用2和2 3 5 7 相乘得到最小值是4,唉,不是3啊。可是如果2和2相乘 而3 5 7 还是和1相乘,那最小值不就是3了。YES!这是个规律。此时得到了2  3 ,如果用2和2相乘,3和2相乘,5 7 和1相乘,那么最小值就是4,OK,我发现新大陆了。	这个表达式好像就是用2 3 5 7和已经得到的Humber Number相乘啊。
	继续找规律,得到了4,那么如何得到5?3和2相乘,2和3相乘,1和5相乘,1和7相乘最小值就是5。和2 3 5 7 相乘的数就是之前的Humber Number,可是是哪个呢?根据刚才的规律我我们可以判断的是,一开始1,如果这个数和2 3 5 7 中的一个相乘得到的结果是最小值,那么就往后推一个Humber Number,也就是Humber数组的i++。如果有重复的都给他++。
	得到状态转移方程 humble[i]=FMin(humble[p2]*2,humble[p3]*3,humble[p5]*5,humble[p7]*7);
编码

#include <iostream>   
using namespace std;

//求所有的Humble Number
void  HumbleNumber(long int humble[],int n);
long int FMin(long int m,long int n,long int k,long int l);    
int main()
{	
	int nums;
	int number;
	long int humble[5843];
	HumbleNumber(humble,5842);
	while(cin>>number)
	{
		if(0==number)
			break;

		//输出格式
		if((number>=4)&&(number<=20))
			cout<<"The "<<number<<"th humble number is "<<humble[number]<<"."<<endl; //英语差了这个题别想AC了。。。
		else if(1==(number-(number/10)*10))
			cout<<"The "<<number<<"st humble number is "<<humble[number]<<"."<<endl;
		else if(2==(number-(number/10)*10))
			cout<<"The "<<number<<"nd humble number is "<<humble[number]<<"."<<endl;
		else if(3==(number-(number/10)*10))
			cout<<"The "<<number<<"rd humble number is "<<humble[number]<<"."<<endl;
		else
			cout<<"The "<<number<<"th humble number is "<<humble[number]<<"."<<endl; 
	}
	return 0;
}


//求所有的Humble Number
void  HumbleNumber(long int humble[],int n)
{
	int i;
	int p2,p3,p5,p7;
	p2=p3=p5=p7=1;
	humble[1]=1;
	for(i=2;i<=n;i++)
	{
		humble[i]=FMin(humble[p2]*2,humble[p3]*3,humble[p5]*5,humble[p7]*7);
		if(humble[i]==humble[p2]*2)//不用else if 为了重复的
			p2++;
		if(humble[i]==humble[p3]*3)
			p3++;
		if(humble[i]==humble[p5]*5)
			p5++;
		if(humble[i]==humble[p7]*7)
			p7++;
	}
}

long int FMin(long int m,long int n,long int k,long int l)
{
	long int min1,min2;
	if(m<=n)
		min1=m;
	else
		min1=n;
	if(k<=l)
		min2=k;
	else
		min2=l;
	if(min1<=min2)
		return min1;
	else
		return min2;
}

	时间复杂度是O(N),就是在5842次就可以全部求出了,然后给定的N就可以O(1),得到结果了。很不错的算法。没有超时,nice!可是结果错误,我那个迷茫啊,彷徨啊。。可是仅仅发现输出结果少了一个尾号”.”,我赶紧添上,又是失败,看来不是这个问题,再说这也该是格式错误的提示啊。。
	最后我查了资料才发现,这个英语真心坑啊,看来不是4-20是th,判断的时候不仅仅是最后一位,还和最后两位有关系啊。。真心跪了。。
最后一次提交!!!

#include <iostream>   
using namespace std;

//求所有的Humble Number
void  HumbleNumber(long int humble[],int n);
long int FMin(long int m,long int n,long int k,long int l);    
int main()
{	
	int nums;
	int number;
	long int humble[5843];
	HumbleNumber(humble,5842);
	while(cin>>number)
	{
		if(0==number)
			break;
		//输出格式
		if((1==number%10)&&(11!=number%100))
			cout<<"The "<<number<<"st humble number is "<<humble[number]<<"."<<endl;
		else if((2==number%10)&&(12!=number%100))
			cout<<"The "<<number<<"nd humble number is "<<humble[number]<<"."<<endl;
		else if((3==number%10)&&(13!=number%100))
			cout<<"The "<<number<<"rd humble number is "<<humble[number]<<"."<<endl;
		else
			cout<<"The "<<number<<"th humble number is "<<humble[number]<<"."<<endl; 
	}
	return 0;
}


//求所有的Humble Number
void  HumbleNumber(long int humble[],int n)
{
	int i;
	int p2,p3,p5,p7;
	p2=p3=p5=p7=1;
	humble[1]=1;
	for(i=2;i<=n;i++)
	{
		humble[i]=FMin(humble[p2]*2,humble[p3]*3,humble[p5]*5,humble[p7]*7);
		if(humble[i]==humble[p2]*2)//不用else if 为了重复的
			p2++;
		if(humble[i]==humble[p3]*3)
			p3++;
		if(humble[i]==humble[p5]*5)
			p5++;
		if(humble[i]==humble[p7]*7)
			p7++;
	}
}

long int FMin(long int m,long int n,long int k,long int l)
{
	long int min1,min2;
	if(m<=n)
		min1=m;
	else
		min1=n;
	if(k<=l)
		min2=k;
	else
		min2=l;
	if(min1<=min2)
		return min1;
	else
		return min2;
}


成功!!鲜红的Accepted,很有成就感啊。
总的来说这个题是不难的,只要用心去想肯定可以AC,这也算是很简单的DP啦。不得不吐槽的是和英语太有关系了。。。
转载请注明出处http://blog.csdn.net/liangbopirates/article/details/9632829




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

HDOJ 1058 Humble Numbers解题报告【DP】 的相关文章

  • 周志华《机器学习》笔记(第4章) 决策树

    第四章 决策树 1 总述 决策树基于树结构进行决策 叶结点对应于决策结果 其他每个结点对应于一个属性测试 每个结点包含的样本集合根据属性测试的结果被划分到子结点中 最终目的是产生一个泛化能力强 能够处理未知样本的决策树 基本流程遵循简单而直
  • XSS学习

    目录 什么是XSS 概念 理解 XSS分类 存储型XSS 反射型XSS 原理 攻击过程 DOM型 攻击过程 DOM行XSS与反射型XSS区别 存储型XSS与反射型XSS区别 DVWA实验 反射型XSS low等级 JavaScript弹窗函
  • 2013年第四届C/C++ A组蓝桥杯省赛真题解析

    目录 第一题 高斯日记 题目描述 思路分析 AC代码 第二题 排它平方数 题目描述 思路分析 AC代码 第三题 振兴中华 题目描述 思路分析 AC代码 第四题 颠倒的价牌 题目描述 思路分析 AC代码 第五题 前缀判断 题目描述 思路分析

随机推荐

  • 将文件从本机上传到虚拟机中Linux系统中的几种方法

    一 使用FileZilla上传文件 1 启动虚拟机 打开Linux终端 输入ifconfig命令查看IP地址 IP地址为192 168 59 6 2 打开FileZilla 输入IP地址 用户名 密码 端口号 点击快速连接 连接成功后 左边
  • 测试工程师(初&中)面试题+知识点

    说明 记录下个人开始转行自学 gt 开始求职期间主要的学习内容 涵盖了 计算机基础 测试基础 自动化测试等 初中级测试 20年夏更新 需要掌握的大部分内容 巩固基础与按知识点自查时可选择性参考 一 面试题 1 请分别介绍一下单元测试 集成测
  • 芯片的SD/MMC控制器以及SD卡介绍

    1 MMC SD卡 eMMC介绍 1 1 三者关联 1 最早出现的是MMC卡 卡片式结构 按照MMC协议设计 相较于NandFlash芯片来说 MMC卡有2个优势 第一是卡片化 便于拆装 第二是统一了协议接口 兼容性好 2 后来出现SD卡
  • 数据库---mysql 之 常用命令行命令

    1 展示当前所有的数据库 show databases mysql gt show databases Database information schema jzq test mtx 1 mysql performance schema
  • 使用特网云云主机的最显着原因之一

    云计算的快速发展主要是由于移动设备的数量不断增加 云不仅对企业有用 对普通人也有用 我们无需在 PC 上安装程序即可运行程序 通过 Internet 存储和访问内容 无需物理服务器即可开发和测试程序 等等 云计算本质上是我们解决当今企业面临
  • 序列化的简介

    序列化 序列化的介绍 1 1 定义 序列化是将对象状态转换为可保持或传输的格式的过程 与序列化相对的是反序列化 它将流转换为对 象 这两个过程结合起来 可以轻松地存储和传输数据 1 2 序列化的目的 通过序列化以字节流的形式使对象在网络中进
  • 为什么别选计算机专业?

    在知乎看到一个这样的问题 为什么别选计算机专业 这个话题有 800 万人次浏览 以下是一位匿名用户的高赞回答 内容可能比较主观化 仅代表原作者个人观点 如果有不同意见欢迎留言区交流啊 不明白现在鼓吹计算机是什么意思 985计算机毕业 刷Le
  • 广东海洋大学数学与计算机学院校友会,2020年广东海洋大学数学与计算机学院全日制硕士研究生入学考试复试及录取工作方案...

    为规范我校全日制硕士研究生复试工作 保障研究生入学质量 依据教育部有关文件及广东省研究生招生录取工作会议精神 结合学校今年硕士研究生招生工作的实际情况 特制定本工作方案 一 工作原则 研究生复试工作要坚持公开 公平 公正和科学选拔的原则 德
  • 【C++】继承详解

    文章目录 继承的概念 基类和派生类对象赋值转换 继承作用域 派生类的默认成员函数 继承和友元 静态成员变量的继承 菱形继承和虚拟继承 继承和组合 继承的概念 继承机制是面向对象程序设计使代码复用的重要手段 通过继承机制 可以利用已有的数据类
  • C++基础4:构造函数、析构函数、拷贝析构函数、静态成员函数

    构造函数 1 1构造函数 一个特殊的函数与类型名相同 没有返回值类型 保证创建一个对象时 自动调用一次 一个类可以有多个构造函数 作用 初始化对象 如果一个类不提供构造函数 则系统自动提供一个无参构造函数 但一旦提供构造函数 则系统的无参构
  • Head-Free Lightweight Semantic Segmentation with Linear Transformer 新颖的分割网络

    现有的语义分割网络基本都是编码解码结构 新的语义分割网络主要都是在解码阶段添加新的不同模块 提高解码阶段特征处理能力 从而实现语义分割 而这篇文章主要是去除了解码阶段 把工作重心放在了编码阶段 它采用并行架构来利用原型表示作为特定的可学习的
  • Linux Mii management/mdio子系统分析之六 fixed-mii_bus分析(mac2mac分析)

    前面几章我们介绍了MDIO模块的大部分内容 针对mii bus mdio bus phy device phy driver相关的注册 注销均进行了介绍 基本上把mdio模块的内容介绍完了 而本篇介绍的内容 主要是针对虚拟mii bus实现
  • python类基本语法笔记

    语言是工具 一段时间不用就会忘掉语法 静态方法和类方法 什么时候会用到这样的方法呢 类方法是针对类存在的 可以用类直接调用 主要用到的两个函数是staticmethod 和classmethod 简洁的用法是用Python的修饰器 需要注意
  • Vue总结第二天~自定义子组件、父子组件通信、插槽

    目录 一 组件 组件目录 1 注册组件 全局组件 局部组件和demo template模块 1 注册组件的基本步骤 2 全局组件demo 3 局部组件demo 4 template模块的简化 模板的分离写法 即将其内容封装到 templat
  • Matplotlib

    1 折线图 import matplotlib pyplot as plt import numpy as np x np linspace 1 1 50 1到1 有五十个点 y 2 x 1 plt figure num 1 figsize
  • 【计算机网络】第一章:计算机网络概述

    文章目录 1 1 计算机网络在信息时代的作用 1 2 因特网概述 1 3 三种交换方式 1 4 计算机网络的定义和分类 1 5 计算机网络的性能指标 1 6 计算机网络体系结构 计算机网络体系结构 计算机网络体系结构分层的必要性 计算机网络
  • 从gitHub当中更新项目synchronize Update fetch pull 项目的区别。

    11 从gitHub更新项目 方法一 右击你的项目 team synchronize workspace 这样他就会去gitHub那fetch回最新的版本 之后像svn一样 切换到team synchronize视图 注意服务器如有更新 而
  • Vue之插件的介绍

    简介 主要介绍Vue插件的概念 定义和使用 Vue的插件主要是用于增强功能 可以把它看作是一个工具库 可以提供很多强大的功能 比如一些强大的自定义指令 一些强大的工具方法 过滤器等 我们可以编写或者直接引入别人写的插件 就能获得强大的功能
  • odoo 权限

    创建安全组并分配用户 Odoo中的访问权限通过安全组成进行配置 给组指定权限 然后为组分配用户 每个功能区都有中枢应用所提供的基础安全组 在插件继承已有应用时 它们应对相应的组添加权限 参见本章稍后的向模型添加访问权限一节 在插件模块添中添
  • HDOJ 1058 Humble Numbers解题报告【DP】

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