当前位置: 首页 > news >正文

csp知识基础——贪心算法

核心原则:局部最优会导致全局最优

用几个题目来感受一下:

t1接水问题和t2导弹拦截方案


t1:多水龙头接水

有n个人,每个人打水时间不一样,但打水顺序已经定了,一共m个水龙头,求总用时最短。

输入:

5 3
4 4 1 2 1

输出:

4

一开始,我理解错了,我以为打水顺序可以变,所以先排序再安排打水,因为打水时间=接水时间+排队时间,所以在每个人接水时间固定下,让排队时间最小即可。输出结果一直不对,最后问了AI才发现自己粗心没看到说排队时间已经固定。。。

解析:第一波打水 4 4 1,下面就是,

2去了(4 4 1)中的三号位,用时1+2=3,

1去了(4 4 3)中的三号位,用时3+1=4

所以关键就是找到并更新最小打水时间,用优先队列的方法比较好,复习一下优先队列的用法:

1,priority_queue< int > a;     // 基础类型, 默认是大顶堆,自动排

2,priority_queue<int, vector< int >, greater< int > > c;     //基础类型,变小根堆

#include <bits/stdc++.h>
using namespace std;
using ll = long long;int main() {int n, m;cin >> n >> m;vector<int> w(n);for (int i = 0; i < n; i++) cin >> w[i];// 小根堆存水龙头结束时间priority_queue<ll, vector<ll>, greater<ll>> pq;// 先让前 m 个人上for (int i = 0; i < m; i++) {pq.push(w[i]);}// 后续的人找最早空闲的水龙头for (int i = m; i < n; i++) {ll t = pq.top(); pq.pop();pq.push(t + w[i]);}// 最后的答案是最大结束时间ll ans = 0;while (!pq.empty()) {ans = max(ans, pq.top());pq.pop();}cout << ans << "\n";return 0;
}

然后后面是我自己的方法,不符合题意的那种。。。但也敲了好久,我最后输出数据表示,这个总用时比上面的方法还要长,这我就不太理解了。。。有懂的大佬可以回复一下嘛。。

#include <bits/stdc++.h>
#define ll long long
using namespace std;int main() {ll n;int m; // n 人,m 个水龙头cin >> n >> m;vector<ll> a(n+1);for (ll i = 1; i <= n; i++) cin >> a[i];sort(a.begin() + 1, a.end()); // 时间短的先打,理解错了题意//求最短打水时间  已知每个人的时间是 排队时间+打水时间,那么让排队时间最短即可。即//1.先排序,按时间大小进行排序//2.计算每个人的打水时间,第一波人,时间=打水时间;第二波人,时间=排队时间(第一波人时间)+打水时间//3....依次计算出最后那个人的打水时间//4.发现规律:第m+1个人在第1个后面,即1~m+1~2m+1...,2~m+2~2m+2...所以,要想知道最后一个人的打水时间,只需要看他是第几组即可if (n <= m) { // 一波打完cout << a[n] << endl;return 0;}// 最后一个人的列位置 (从 1 开始)int col = (n - 1) % m + 1;ll ans = 0;// 同一列上的人: col, col+m, col+2m, ...for (ll i = col; i <= n; i += m) {ans += a[i];}cout << ans << endl;
}

t2:导弹拦截方案

我理解的意思是:炮弹的发送顺序已经确定,现在用一个系统墙壁进行防御,每次会打坏上面的部分,即假设系统1初始高度>=389,在第一发过来之后,高度就变成了=389,第二发过来之后,高度就变成了207,第三发过来后就变成了175,那么第四发300过来,系统1(175)明显挡不住了,就需要在后面加一套系统,我们叫他系统2防御墙(>=300),它阻挡第四发300后,变成了300,第五发299也得系统2(300)来挡,系统2变成了299,第六发170可以被系统1(175)挡住,即系统1变成170,第七发158还是可以被系统1(170)挡住,变成158,最后一发165,就只能被系统2(299)挡住了,,,问题本质上是最少非递增子序列划分问题,贪心就是每次把导弹分到最合适的现有系统里。

所以一共需要两套系统,每套系统可以阻拦的炮弹也如上图所示,该题的做法就是不断更新系统能拦截的最大高度,不能拦截就再加一套系统,继续从头遍历系统,能拦截就拦截,不能就加一套系统。。。

#include <bits/stdc++.h>
using namespace std;int main() {ios::sync_with_stdio(false);cin.tie(nullptr);int h;vector<int> missiles;while (cin >> h) { // 读到输入结束missiles.push_back(h);}struct System {int height;           // 当前系统可拦的最大高度vector<int> sequence; // 该系统拦下的导弹序列};vector<System> systems;for (int m : missiles) {bool blocked = false;for (auto &sys : systems) {if (sys.height >= m) { // 该系统可以拦sys.height = m;    // 更新高度sys.sequence.push_back(m);blocked = true;break;}}if (!blocked) { // 新建系统systems.push_back({m, {m}});}}cout << systems.size() << "\n"; // 输出最少系统数for (size_t i = 0; i < systems.size(); i++) {cout << "系统 " << (i + 1) << " : 拦截 ";for (size_t j = 0; j < systems[i].sequence.size(); j++) {cout << systems[i].sequence[j];if (j + 1 < systems[i].sequence.size()) cout << " ";}cout << "\n";}return 0;
}

http://www.xdnf.cn/news/1292815.html

相关文章:

  • 类和对象(中下)
  • 图像分类-动手学计算机视觉10
  • JDK17下载与安装图文教程(保姆级教程)
  • 基于DDPG的车辆纵向速度控制优化:兼顾速度与乘坐舒适性
  • 《Python学习之基础语法1:从零开始的编程之旅》
  • k8s资源管理
  • GPT-o3回归Plus用户,GPT5拆分三种模式,对标Grok
  • 什么是HTTP的无状态(举例详解)
  • 【C++详解】用红黑树封装模拟实现mymap、myset
  • 【C++】哈希的应用:位图和布隆过滤器
  • Query通过自注意力机制更新(如Transformer解码器的自回归生成)的理解
  • 【Java web】HTTP 与 Web 基础教程
  • 最新去水印小程序系统 前端+后端全套源码 多套模版 免授权
  • 弹性扩展新范式:分布式LLM计算的FastMCP解决方案
  • 可视化调试LangChain SQLChatMessageHistory:SQLite数据库查看全攻略
  • 6 ABP 框架中的事件总线与分布式事件
  • 服务器安全检测与防御技术总结
  • 比特币与区块链:去中心化的技术革命
  • Java毕业设计选题推荐 |基于SpringBoot的水产养殖管理系统 智能水产养殖监测系统 水产养殖小程序
  • TensorFlow实现回归分析详解
  • 把 Linux 装进“小盒子”——边缘计算场景下的 Linux 裁剪、启动与远程运维全景指南
  • 各种排序算法(二)
  • 升级Gradle版本后,安卓点击事件使用了SwitchCase的情况下,报错无法使用的解决方案
  • PCBA:电子产品制造的核心环节
  • MCP协议更新:从HTTP+SSE到Streamable HTTP,大模型通信的进化之路
  • 记某一次仿真渗透测试
  • 开发Excel Add-in的心得笔记
  • [系统架构]系统架构基础知识(一)
  • 基于elk实现分布式日志
  • 2025 开源语音合成模型全景解析:从工业级性能到创新架构的技术图谱