[NOI Online #1 入门组] 文具订购

news2025/1/31 16:49:41

题目描述:

小明的班上共有 n 元班费,同学们准备使用班费集体购买 3 种物品:

  1. 圆规,每个 7 元。
  2. 笔,每支 4 元。
  3. 笔记本,每本 3 元。

小明负责订购文具,设圆规,笔,笔记本的订购数量分别为 a,b,c,他订购的原则依次如下:

  1. n 元钱必须正好用光,即 7a+4b+3c=n。
  2. 在满足以上条件情况下,成套的数量尽可能大,即 a,b,c 中的最小值尽可能大。
  3. 在满足以上条件情况下,物品的总数尽可能大,即 a+b+c 尽可能大。

请你帮助小明求出满足条件的最优方案。可以证明若存在方案,则最优方案唯一。

输入格式:

输入仅一行一个整数,代表班费数量 n。

输出格式:

如果问题无解,请输出 -1。

否则输出一行三个用空格隔开的整数 a, b, c,分别代表圆规、笔、笔记本的个数。

输入输出样例:

输入 #1:

1

输出 #1:

-1

输入 #2:

14

输出 #2:

1 1 1

输入 #3:

33

输出 #3:

1 2 6

说明/提示:

样例输入输出 3 解释:

a=2,b=4,c=1 也是满足条件 1,2的方案,但对于条件 3,该方案只买了 7 个物品,不如 a=1,b=2,c=6 的方案。

数据规模与约定:

  • 对于测试点 1∼6,保证 n≤14。
  • 对于测试点 7∼12,保证 n 是 14 的倍数。
  • 对于测试点 13∼18,保证 n≤100。
  • 对于全部的测试点,保证 0≤n≤10^5。

 思路:

  看到这道题,我们有两个思路:

  1.暴力法

  第一个就是暴力,暴力三重循环a,b,c依次枚举,先定义一个计数器sum,初始化为0,如果三重循环过后还是为0,那么代表没有任何一个方案,输出-1.

  最开始还要定义三个变量x,y,z代表着最优方案,我们在暴力循环中科院和目前最优方案x,y,z进行比较,如果a,b,c在小明的订购原则中是大于x,y,z的那么就将x,y,z重新赋值a,b,c。

  在循环中,a,b,c如果符合条件第一个条件,将计数器sum加上1,然后我们进行第一优先级的判断,我们可以写一个函数check来判断,参数为a,b,c.(因为x,y,z是全局变量,不用多加变量)返回值为int类型,如果a,b,c的最小值大于x,y,z的最小值就返回1(之后要重新赋值x,y,z),如果相等,返回-1,代表之后需要进行第二优先级的比较,如果小于,返回0,之后不用更新x,y,z的值。

int check(int a,int b,int c){ //第一优先级(最小值尽可能大) 
	if(min(a,min(b,c))>min(x,min(y,z))) //如果a,b,c的最小值大于x,y,z的最小值 
	  return 1; //返回1(之后将x,y,z赋值为a,b,c) 
	else if(min(a,min(b,c))==min(x,min(y,z))) //如果两者优先级相同 
	  return -1; //返回-1(之后进行第二优先级比较) 
	return 0; //如果a,b,c的最小值小于x,y,z的最小值(不用管) 
}

  以上代码是第一优先级函数的判断,接下来我们需要写第二优先级函数pd的判断(参数为a,b,c,返回值为bool,不可能相等了,因为题目说了,数据保证只有一个最优方案).

  我们第二优先级是在第一优先级相等的条件下让a,b,c之和尽可能的大,我们这个函数只需要判断a+b+c和x+y+z的值谁的大就行了!

bool pd(int a,int b,int c){ //第二优先级(三者相加尽可能大) 
	if(a+b+c>x+y+z) //如果大于 
	  return true; //返回真(之后x,y,z赋值为a,b,c) 
	return false; //返回假(不用管) 
}

  之后经过三重循环查找最优购买方案后,输出x,y,z就行了。(三重循环,复杂度为O(n^3)).

  2.暴力法代码:

//暴力法O(n^3): 
#include<bits/stdc++.h> //万能头文件 
using namespace std; //批注使用std类 
int x=0,y=0,z=0; //分别为购买三类物品的最优方案 
int check(int a,int b,int c){ //第一优先级(最小值尽可能大) 
	if(min(a,min(b,c))>min(x,min(y,z))) //如果a,b,c的最小值大于x,y,z的最小值 
	  return 1; //返回1(之后将x,y,z赋值为a,b,c) 
	else if(min(a,min(b,c))==min(x,min(y,z))) //如果两者优先级相同 
	  return -1; //返回-1(之后进行第二优先级比较) 
	return 0; //如果a,b,c的最小值小于x,y,z的最小值(不用管) 
}
bool pd(int a,int b,int c){ //第二优先级(三者相加尽可能大) 
	if(a+b+c>x+y+z) //如果大于 
	  return true; //返回真(之后x,y,z赋值为a,b,c) 
	return false; //返回假(不用管) 
}
int main(){ //main主函数 
	int n,sum=0; //定义 
	cin>>n; //输入
	//三重循环找最优方案 
	for(int a=0;a<n;a++){ //枚举圆规数量 
		for(int b=0;b<n;b++){ //枚举笔数量 
			for(int c=0;c<n;c++){ //枚举笔记本数量 
				if((7*a+4*b+3*c)==n){ //如果钱数刚好符合要求 
					sum++; //计数器++ 
					int f=check(a,b,c); //进行第一优先级比较 
					if(f==1) //如果为1 
					  x=a,y=b,z=c; //重新赋值 
					else if(f==-1){ //如果相等 
						if(pd(a,b,c)) //进行第二优先级比较 
						  x=a,y=b,z=c; //如果为真,重新赋值 
					}
				}				
			}

		}
	}
	if(sum==0) //如果计数器为0 
	  cout<<"-1"<<endl; //无方案,输出-1 
	else //不为0 
	  cout<<x<<" "<<y<<" "<<z<<endl; //输出最优方案 
	return 0; //结束 
}

  3.暴力优化法

   我们可以对暴力法进行一下优化,怎么优化呢?

  首先,我们知道,7a+4b+3c=n,那么我们可以只用枚举其中两个物品的订购方案,为什么呢?假如我们枚举c和b的购买方案,我们可以求出a来怎么求呢?首先4*b+3*c必须小于等于n,这样a才可以为正数,还有:因为题目要求,a,b,c必须都是正整数,所以a不能为小数,我们知道如果4*b+3*c<=n的话,那么(n-4*b-3*c)就等于7*a,为了确保a是整数,所以我们需要判断(n-4*b-3*c)除以7的余数 为不为0,如果为0,那么a是整数,就可以求a,不为0,那么就不是整数,不继续进行。

  这样我们只用了两重循环就解决了这个问题,复杂度为O(n^2)。

  4.暴力优化法代码:

//优化O(n^2): 
#include<bits/stdc++.h> //万能头文件 
using namespace std; //批注使用std类 
int x=0,y=0,z=0; //分别为购买三类物品的最优方案 
int check(int a,int b,int c){ //第一优先级(最小值尽可能大) 
	if(min(a,min(b,c))>min(x,min(y,z))) //如果a,b,c的最小值大于x,y,z的最小值 
	  return 1; //返回1(之后将x,y,z赋值为a,b,c) 
	else if(min(a,min(b,c))==min(x,min(y,z))) //如果两者优先级相同 
	  return -1; //返回-1(之后进行第二优先级比较) 
	return 0; //如果a,b,c的最小值小于x,y,z的最小值(不用管) 
}
bool pd(int a,int b,int c){ //第二优先级(三者相加尽可能大) 
	if(a+b+c>x+y+z) //如果大于 
	  return true; //返回真(之后x,y,z赋值为a,b,c) 
	return false; //返回假(不用管) 
}
int main(){ //main主函数 
	int n,sum=0; //定义 
	cin>>n; //输入
	for(int c=0;c<=n;c++){ //枚举笔记本数量
		for(int b=0;b<=n;b++){ //枚举笔数量 
			if((3*c+4*b)<=n&&(n-(3*c+4*b))%7==0){ //进行判断条件一是否符合 
				sum++; //计数器++ 
				int a=(n-(3*c+4*b))/7; //求出a 
				int f=check(a,b,c); //进行第一优先级判断 
				if(f==1) //如果为1 
				  x=a,y=b,z=c; //重新赋值 
				else if(f==-1){ //如果相等 
					if(pd(a,b,c)) //进行第二优先级判断 
					  x=a,y=b,z=c; //如果为真,重新赋值 
				}
			}
		}
	}
	if(sum==0) //如果没有一个方案 
	  cout<<"-1"<<endl; //输出-1 
	else //如果不是0 
	  cout<<x<<" "<<y<<" "<<z<<endl; //输出我们找到的最优方案 
	return 0; //结束 
}

  这样子,我们复杂度为O(n^2),但是还是会超时,因为n最大为10万,10万的平方铁定超时,所以我们还需要进行优化。

  5.暴力循环优化法:

    接下来,我们需要从暴力优化法继续进行优化,怎么优化呢?

  其实很简单,我们观察b,c.因为4*b+3*c<=n,这说明什么,b<=(n/4) ,c<=(n/3).也就是说,在两重for循环枚举的时候,不需要将b和c都枚举到n了,c只需要枚举到n/3,b只需要枚举到n/4.

  最后,暴力循环优化法的复杂度为O((1/3*n)*(1/4*n))乘法分配律拆开,就是O(1/12*n^2).其实最大我们可以将复杂度简化为O(1/28*n^2).枚举b和c,一个是到n/4,一个是到n/3.如果我们枚举a,b,之后计算c,a是枚举到/7,b不变。

  这样子来说,就不会超时了!

   6.暴力循环优化法代码:

//优化O(n^2): 
#include<bits/stdc++.h> //万能头文件 
using namespace std; //批注使用std类 
int x=0,y=0,z=0; //分别为购买三类物品的最优方案 
int check(int a,int b,int c){ //第一优先级(最小值尽可能大) 
	if(min(a,min(b,c))>min(x,min(y,z))) //如果a,b,c的最小值大于x,y,z的最小值 
	  return 1; //返回1(之后将x,y,z赋值为a,b,c) 
	else if(min(a,min(b,c))==min(x,min(y,z))) //如果两者优先级相同 
	  return -1; //返回-1(之后进行第二优先级比较) 
	return 0; //如果a,b,c的最小值小于x,y,z的最小值(不用管) 
}
bool pd(int a,int b,int c){ //第二优先级(三者相加尽可能大) 
	if(a+b+c>x+y+z) //如果大于 
	  return true; //返回真(之后x,y,z赋值为a,b,c) 
	return false; //返回假(不用管) 
}
int main(){ //main主函数 
	int n,sum=0; //定义 
	cin>>n; //输入
	for(int c=0;c<=(n/3);c++){ //枚举笔记本数量
		for(int b=0;b<=(n/4);b++){ //枚举笔数量 
			if((3*c+4*b)<=n&&(n-(3*c+4*b))%7==0){ //进行判断条件一是否符合 
				sum++; //计数器++ 
				int a=(n-(3*c+4*b))/7; //求出a 
				int f=check(a,b,c); //进行第一优先级判断 
				if(f==1) //如果为1 
				  x=a,y=b,z=c; //重新赋值 
				else if(f==-1){ //如果相等 
					if(pd(a,b,c)) //进行第二优先级判断 
					  x=a,y=b,z=c; //如果为真,重新赋值 
				}
			}
		}
	}
	if(sum==0) //如果没有一个方案 
	  cout<<"-1"<<endl; //输出-1 
	else //如果不是0 
	  cout<<x<<" "<<y<<" "<<z<<endl; //输出我们找到的最优方案 
	return 0; //结束 
}

总结:

  其实这三种方法代码都非常的相同,但是时间复杂度却大不一样,说明,一个复杂度极高的代码,只要你细心观察,稍微在关键点改上几笔,可能就比之前快上许多倍呢!

题目链接:

[NOI Online #1 入门组] 文具订购 - 洛谷https://www.luogu.com.cn/problem/P6188

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/193516.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux 下安装 JDK 和 Maven 环境

目录 1. 进入 maven 官网下载安装包 2. 安装 maven 3. 添加 Maven 环境变量 4. 配置 Maven 本地仓库 5. 配置镜像 6. 配置 JDK 7. 测试 操作系统&#xff1a;Centos 7.6 安装 maven 环境前&#xff0c;需要先安装 java 环境&#xff0c;笔者这里已经成功安装 java 环境&…

PHP基础知识 - PHP面向对象OOP

目录 一. 面向对象基本知识 1.1 面向对象概念 1.2 什么是类 1.3 什么是对象 1.4 类与对象的关系 1.5 PHP创建类的示例 二、类、属性、方法的修饰符 2.1 类的修饰符 2.2 成员方法的修饰符 2.3 成员属性修饰符 2.4 访问控制修饰符 2.5 static 静态修饰符 2.6 final…

多模块项目中,SpringBoot项目下启动失败-无法加载主类com.xch.XxxApplication

错误&#xff1a;项目启动时&#xff0c;无法找到主类(启动类)XxxApplication由于&#xff0c;主类需要先被编译&#xff0c;再被JVM找到编译后的文件运行如&#xff1a;XxxApplication.java-(编译)-XxxApplication.class-(运行)所以&#xff0c;原因&#xff1a;1、未编译情况…

基于微信小程序的校运会管理系统

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端框架&#xff1a;VUE 数据库&#xff1a;MySQL5.7以上 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#xff1a;是 目录 一、项目简介…

Erlik 2:一个基于Flask开发的包含大量安全漏洞的研究平台

关于Erlik 2 Erlik 2&#xff0c;也被称为Vulnerable-Flask- App&#xff0c;该工具是一个基于Flask开发的包含大量安全漏洞的研究平台。本质上来说&#xff0c;它是一个包含了大量漏洞的Flask Web应用程序。有了这个实验环境&#xff0c;广大研究人员可以轻松在Web渗透测试领…

【算法题解】14. 有效的括号

文章目录题目解法&#xff1a;使用栈的特性Java 代码实现Go 代码实现复杂度分析这是一道 简单 题。 来自&#xff1a;leetcode 题目 给定一个只包括 (&#xff0c;)&#xff0c;{&#xff0c;}&#xff0c;[&#xff0c;] 的字符串 s &#xff0c;判断字符串是否有效。 有效字…

哈工大操作系统学习笔记(二)进程与线程

文章目录CPU管理的直观想法多进程图像用户级线程内核级线程内核级线程实现操作系统之树CPU 调度策略一个实际的schedule 函数进程同步与信号量信号量临界区保护信号量的代码实现死锁处理CPU管理的直观想法 CPU的工作原理&#xff1a; 自动的取值执行&#xff0c;给了初始地址&…

Swift 周报 第二十一期

前言 本期是 Swift 编辑组自主整理周报的第十二期&#xff0c;每个模块已初步成型。各位读者如果有好的提议&#xff0c;欢迎在文末留言。 Swift 周报在 GitHub 开源&#xff0c;欢迎提交 issue&#xff0c;投稿或推荐内容。目前计划每两周周一发布&#xff0c;欢迎志同道合的…

永久删除的照片怎么找回来?教你三招恢复方法

如果文件被永久删除了&#xff0c;想要恢复就没有这么简单了&#xff0c;永久删除的文件可能是已经从回收站清空的文件&#xff0c;或者是我们按住快捷键“shiftdelete”快捷键删除的文件&#xff0c;这样的话&#xff0c;我们无法在电脑上面查找到文件&#xff0c;潜意识里面认…

SAP ABAP SY-REPID 变化「Note」

6.10 前&#xff08;知悉&#xff09; SY-CPROG The name of the calling program in an external routine, otherwise the name of the current program. 外部例程中调用程序的名称&#xff0c;否则为当前程序的名称 SY-REPID Name of the current ABAP program. For externa…

第一章-操作系统引论

&#x1f31e;欢迎来到操作系统的世界 &#x1f308;博客主页&#xff1a;卿云阁 &#x1f48c;欢迎关注&#x1f389;点赞&#x1f44d;收藏⭐️留言&#x1f4dd; &#x1f31f;本文由卿云阁原创&#xff01; &#x1f64f;作者水平很有限&#xff0c;如果发现错误&#xff…

解决数据兼容性问题

数据兼容性问题解决 问题说明 最近经常遇到新老数据兼容性的问题&#xff1a;某些新同事更改代码后&#xff0c;没有兼容旧数据&#xff0c;已有用户的数据显示不全或者错误&#xff0c;很麻烦。 技术层面&#xff0c;就是某个数据或者字段&#xff0c;存储在服务器上&#…

java后端工程师面试题(笔试):2022-11-04 经历(一)

java后端工程师面试题&#xff08;笔试&#xff09;&#xff1a;2022-11-04&#xff1a; 面试题&#xff1a;总分100 1、关于盒子模型(5分) 1&#xff09;盒子模型的种类有几种?分别是什么?(1分) 2种&#xff0c;分别是1、W3C标准盒子模型 2、IE盒子模型2) 容器中使用di…

射频已调波同步广播技术在山区高速公路同步广播建设中的应用

北京恒星科通发布于2023-2-2 我国高速公路建设速度的加快&#xff0c;目前我国已经建成通车的高速公路总里程已经达到14万公里&#xff0c;高速公路的安全与信息化建也达到了快速发展&#xff0c;高速公路调频广播覆盖一直是困扰高速公路管理方的一个重要问题&#xff0c;我国…

实时分析全面赋能金融业务,马上消费基于 Apache Doris 构建实时数仓的实践

导读&#xff1a; 近年来&#xff0c;马上消费的业务体量呈飞跃式增长&#xff0c;每天产生数据可达上千亿条&#xff0c;如何更高效挖掘这些数据的价值&#xff0c;成为了其必须要面临的挑战。随着各业务对实时数据分析的需求越来越强烈&#xff0c;马上消费于 2021 年引入 Ap…

点云处理指南介绍

目录 一、点云处理介绍&#xff1a; 二、Open3D文章目录&#xff1a; Open3D几何部分&#xff08;Geometry&#xff09; 点云处理&#xff08;点云IO/可视化/数据结构/下采样/凸包计算/裁减/法向量估计/聚类/隐藏点移除/平面分割/最小外接矩形/外点移除&#xff09; 面片&…

HTML5+CSS3(三)-全面详解(学习总结---从入门到深化)

目录 Form表单 表单元素 学习效果反馈 表单元素一 文本框 密码框 单选按钮 学习效果反馈 表单元素二 复选框 文件 提交按钮 重置按钮 学习效果反馈 表单元素三 下拉列表 多行文本框 label 学习效果反馈 HTML5新增type类型一 url search tel color 学习效果反馈 HTML5新增…

「Python|网页开发」如何使用Django快速开始进行网页开发:写个Hello World!

本文主要介绍如何从零开始借助django框架快速启动一个网页服务器然后进入编写HTML页面的阶段。 文章目录安装django创建并启动网页项目在网页项目中创建一个应用创建页面并设置好对应关系安装django Django是Python的一个第三方库&#xff0c;里面已经将编写网页需要的代码结构…

如何更改报表控件 Stimulsoft BI 服务器中的地址和端口?

在本文中&#xff0c;我们将主要讨论如何在 Stimulsoft BI Server 中设置基本参数&#xff0c;具体来说&#xff0c;也就是如何更改服务器的地址和端口&#xff1f; 为什么需要更改服务器地址和端口&#xff1f; 在部署报表服务器时&#xff0c;需要指定其地址&#xff0c;实…

使用Websockets和Vert.x进行实时竞价

翻译: 白石(https://github.com/wjw465150/Vert.x-Core-Manual) 原文地址: https://vertx.io/blog/real-time-bidding-with-websockets-and-vert-x/ 在过去的几年中&#xff0c;用户对网络应用程序的期望发生了变化。在拍卖竞价过程中&#xff0c;用户不再需要按下刷新按钮来检…