【CSP试题回顾】202303-2-垦田计划

2024-03-05 06:44

本文主要是介绍【CSP试题回顾】202303-2-垦田计划,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

CSP-202303-2-垦田计划

解题关键:二分查找

二分搜索是一种在有序数组中查找特定元素的高效算法。在本题中,二分搜索被用来找到能够在资源限制下完成所有任务的最短时间。这个时间在范围 k(不得少于这个天数)到 taskList[0].timeSpend(所有任务中耗时最长的一个,taskList是以基础耗时的降序顺序排列的容器)之间。

1. 初始化二分搜索的边界

  • 左边界 (left):设置为 k,因为根据问题描述,任务不能在少于 k 天的时间内完成。
  • 右边界 (right):设置为 taskList[0].timeSpend,即所有任务中耗时最长的一个,因为这是在没有任何资源限制的情况下可能需要的最大天数。

2. 进行二分搜索

二分搜索的核心思想是在每一步将搜索范围缩小一半。这是通过更新左边界或右边界来实现的,基于中间点 (mid) 的计算结果:

  • 计算中间点 (mid):在当前的左右边界内找到中间的天数,mid = left + (right - left) / 2。这是当前迭代我们要检查的天数。

  • 检查给定天数是否可行 (canFinish 函数):使用 canFinish 函数判断在给定的资源限制 m 下,是否能够将所有任务的完成时间缩短到 mid 天。这涉及到遍历所有任务,计算如果将它们缩短到 mid 天所需的总资源,并判断这是否超过了可用资源 m

3. 更新搜索边界

  • 如果 mid 天是可行的(即 canFinish(mid, m, taskList) 返回 true),这意味着我们可能还能找到更短的完成时间,同时满足资源限制。因此,我们尝试寻找更小的天数,将右边界 right 更新为 mid - 1

  • 如果 mid 天不可行,意味着我们需要更多的时间来完成所有任务,所以我们将左边界 left 更新为 mid + 1

4. 终止条件

left 大于 right 时,二分搜索结束。此时,left 指向第一个不能满足条件的天数,而 right 指向最后一个能满足条件的天数。因为我们在搜索过程中一直在尝试找到更小的满足条件的天数,所以最终的答案应该是 leftright + 1(它们在循环结束时相等)。

解题思路

  1. 输入处理

    • 读取任务数量 n、可用资源 m 和目标完成天数 k
    • 初始化一个 taskList,然后读取每个任务的基础耗时和每天缩短需要的资源,将这些任务存入 taskList 中。
  2. 任务排序

    • 使用标准库函数 sorttaskList 进行排序,按照任务的基础耗时进行降序排列。这意味着耗时最长的任务会被放在列表的开始位置。
  3. 二分搜索初始化

    • 设置二分搜索的左边界 left 为目标完成天数 k,右边界 right 为任务中最长的基础耗时。设置 answerright,表示初始假设最小可完成天数为最大耗时。
  4. 二分搜索执行

    • 进行二分搜索直到左边界 left 大于右边界 right。在每一步:
      • 计算中间值 mid 作为当前尝试的完成天数。
      • 调用 canFinish 函数,判断在 mid 天内是否可以在不超过资源 m 的条件下完成所有任务:
        • 如果可以(canFinish 返回 true),更新 answermid,并将搜索区间调整为左半部分,即 right 设置为 mid - 1,尝试寻找更小的可行天数。
        • 如果不可以(canFinish 返回 false),将搜索区间调整为右半部分,即 left 设置为 mid + 1,表示需要更多天数来完成任务。

完整代码

【100分-二叉搜索】

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;struct MyTask
{int timeSpend; // 基础耗时int resource; // 每缩短一天需要投入的资源
};int n, m, k;
vector<MyTask> taskList;// 检查是否可以在给定的天数和资源限制下完成所有任务
bool canFinish(int days, int m, vector<MyTask>& taskList) {int totalResourceNeeded = 0;for (const auto& task : taskList) {if (task.timeSpend > days) {totalResourceNeeded += (task.timeSpend - days) * task.resource;if (totalResourceNeeded > m) { // 如果所需资源超过了可用资源,则无法完成return false;}}}return true;
}int main() {cin >> n >> m >> k;for (int i = 0; i < n; i++){MyTask t;cin >> t.timeSpend >> t.resource;taskList.push_back(t);}// 按基础耗时进行排序sort(taskList.begin(), taskList.end(), [](const MyTask& a, const MyTask& b) {return a.timeSpend > b.timeSpend;});int left = k, right = taskList[0].timeSpend, answer = right;// 二分搜索while (left <= right) {int mid = left + (right - left) / 2;if (canFinish(mid, m, taskList)) {answer = mid; // 如果可以完成,则尝试找一个更小的天数right = mid - 1;}else {left = mid + 1; // 如果不可以完成,则需要更多的天数}}cout << answer;return 0;
}

【70分-暴力枚举】

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;struct MyTask
{int timeSpend; // 基础耗时int resource; // 每缩短一天需要投入的资源
};int n, m, k;
vector<MyTask>taskList;bool myCompare(const MyTask& a, const MyTask& b) // 自己定义比较函数
{if (a.timeSpend > b.timeSpend){return true;}return false;
}int main() {cin >> n >> m >> k;for (int i = 0; i < n; i++){MyTask t;cin >> t.timeSpend >> t.resource;taskList.push_back(t);}sort(taskList.begin(), taskList.end(), myCompare); // 按照基础耗时降序排列int timeSpendMax = taskList[0].timeSpend; // 最长的基础耗时for (int i = timeSpendMax - 1; i >= k; i--){int sumResourceSpend = 0; // 本轮消耗资源总和for (const auto& it : taskList) {if (it.timeSpend > i) // 可以缩减时间的任务{sumResourceSpend += (it.timeSpend - i) * it.resource;}}if (sumResourceSpend > m) // 消耗资源总和超过现有资源{cout << i + 1; // 输出上一轮的结果break;}else if (i == k) // 手中现有资源足够缩短至第k天{cout << k;break;}}return 0;
}

请添加图片描述

这篇关于【CSP试题回顾】202303-2-垦田计划的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/775618

相关文章

2024年流动式起重机司机证模拟考试题库及流动式起重机司机理论考试试题

题库来源:安全生产模拟考试一点通公众号小程序 2024年流动式起重机司机证模拟考试题库及流动式起重机司机理论考试试题是由安全生产模拟考试一点通提供,流动式起重机司机证模拟考试题库是根据流动式起重机司机最新版教材,流动式起重机司机大纲整理而成(含2024年流动式起重机司机证模拟考试题库及流动式起重机司机理论考试试题参考答案和部分工种参考解析),掌握本资料和学校方法,考试容易。流动式起重机司机考试技

CSP 2023 提高级第一轮 CSP-S 2023初试题 完善程序第二题解析 未完

一、题目阅读 (最大值之和)给定整数序列 a0,⋯,an−1,求该序列所有非空连续子序列的最大值之和。上述参数满足 1≤n≤105 和 1≤ai≤108。 一个序列的非空连续子序列可以用两个下标 ll 和 rr(其中0≤l≤r<n0≤l≤r<n)表示,对应的序列为 al,al+1,⋯,ar​。两个非空连续子序列不同,当且仅当下标不同。 例如,当原序列为 [1,2,1,2] 时,要计算子序列 [

Java基础回顾系列-第七天-高级编程之IO

Java基础回顾系列-第七天-高级编程之IO 文件操作字节流与字符流OutputStream字节输出流FileOutputStream InputStream字节输入流FileInputStream Writer字符输出流FileWriter Reader字符输入流字节流与字符流的区别转换流InputStreamReaderOutputStreamWriter 文件复制 字符编码内存操作流(

Java基础回顾系列-第五天-高级编程之API类库

Java基础回顾系列-第五天-高级编程之API类库 Java基础类库StringBufferStringBuilderStringCharSequence接口AutoCloseable接口RuntimeSystemCleaner对象克隆 数字操作类Math数学计算类Random随机数生成类BigInteger/BigDecimal大数字操作类 日期操作类DateSimpleDateForma

Java基础回顾系列-第三天-Lambda表达式

Java基础回顾系列-第三天-Lambda表达式 Lambda表达式方法引用引用静态方法引用实例化对象的方法引用特定类型的方法引用构造方法 内建函数式接口Function基础接口DoubleToIntFunction 类型转换接口Consumer消费型函数式接口Supplier供给型函数式接口Predicate断言型函数式接口 Stream API 该篇博文需重点了解:内建函数式

Java基础回顾系列-第二天-面向对象编程

面向对象编程 Java类核心开发结构面向对象封装继承多态 抽象类abstract接口interface抽象类与接口的区别深入分析类与对象内存分析 继承extends重写(Override)与重载(Overload)重写(Override)重载(Overload)重写与重载之间的区别总结 this关键字static关键字static变量static方法static代码块 代码块String类特

Java基础回顾系列-第六天-Java集合

Java基础回顾系列-第六天-Java集合 集合概述数组的弊端集合框架的优点Java集合关系图集合框架体系图java.util.Collection接口 List集合java.util.List接口java.util.ArrayListjava.util.LinkedListjava.util.Vector Set集合java.util.Set接口java.util.HashSetjava

Java基础回顾系列-第九天-数据库编程

Java基础回顾系列-第九天-数据库编程 数据库简介工具包java.sql API 内容与数据库建立连接执行SQL语句数据库检索和更新查询结果SQL类型对应Java类型映射元数据异常 API方法DriverManagerConnectionStatementPreparedStatementCallableStatementResultSetjava.sql.Date批处理、存储过程、事务

Java基础回顾系列-第一天-基本语法

基本语法 Java基础回顾系列-第一天-基本语法基础常识人机交互方式常用的DOS命令什么是计算机语言(编程语言) Java语言简介Java程序运行机制Java虚拟机(Java Virtual Machine)垃圾收集机制(Garbage Collection) Java语言的特点面向对象健壮性跨平台性 编写第一个Java程序什么是JDK, JRE下载及安装 JDK配置环境变量 pathHe

CSP-J基础之数学基础 初等数论 一篇搞懂(一)

文章目录 前言声明初等数论是什么初等数论历史1. **古代时期**2. **中世纪时期**3. **文艺复兴与近代**4. **现代时期** 整数的整除性约数什么样的整数除什么样的整数才能得到整数?条件:举例说明:一般化: 判断两个数能否被整除 因数与倍数质数与复合数使用开根号法判定质数哥德巴赫猜想最大公因数与辗转相除法计算最大公因数的常用方法:举几个例子:例子 1: 计算 12 和 18