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

手撕算法-严刑拷打

题目背景:

给定 m 台“相同”机器(或工作线程、工人等),以及 n 个“任务”或“工作”,每个任务都有一个执行时间。我们需要将这 n 个任务分配到这 m 台机器上,使得所有任务都执行完所需的总时间(完工时间)最小,即要找出一个最优的分配方案,让“最后一台机器”完成任务的时间尽可能早。

解释:

•	有 m 台并行机器。
•	有 n 个任务,每个任务的执行时间分别是 w\_water[0], w\_water[1], \dots, w\_water[n-1]。
•	每台机器可顺序执行若干个任务,但同一个任务不能拆分、不能并行执行。
•	分配完成后,以所有机器中“完成时间最晚”的那台机器的时刻作为本次调度的“完工时间”。
•	要求输出最优分配下的“最小完工时间”。

题目要求:

1.	输入
•	第一行包含两个整数 m, n,分别表示机器数量和任务数量。
•	接下来 n 行(或合并为一行,代码里只是 for i in range(n) 读入),每行一个整数,表示该任务所需执行时间。
2.	输出
•	一个整数,表示任务在 m 台机器上全部执行完毕所需的最短时间(即最小化的“最大完工时间”)。

示例:

•	输入:
3 6
4 5 7 8 2 3

•	输出:
12

代码思路与解释

代码采用 贪心 + 最小堆 的思路:

1.	初始化最小堆
•	先将前 m 个任务(如果任务数 \ge m)分别分配给 m 台机器,放入一个“小根堆”(std::priority_queue<int, std::vector<int>, std::greater<int>>)。
•	堆顶(minTime.top()) 表示“当前机器所累积的执行时间”最少的那台机器。
2.	分配后续任务
•	对于剩余的任务(第 m 个及之后的),取出堆顶的那台机器时间 top,给它分配下一个任务的执行时间,然后再将更新后的总时间推回堆中。
•	这样做保证每次都将新的任务分配给当前最空闲(或时间最短)的机器,在局部层面上看是一种贪心最优。
3.	计算结果
•	最终堆中存的就是 m 台机器各自的“总执行时间”。我们只要找出其中的最大值,就是所有任务完成的完工时间。
•	代码里通过 while (!minTime.empty()) { time = max(time, minTime.top()); minTime.pop(); } 获取堆中最大的时间。

时间复杂度:

•	构建堆为 O(m)(通常可以视为 O(\min(m,n)))。
•	遍历后续 n - m 个任务时,每次取堆顶 + 插入堆都要 O(\log m)。
•	综合起来是 O(n \log m),适用于 n 远大于 m 的场景。

代码:

#include <iostream>
#include <vector>
#include <queue>
#include <algorithm> // for max

int water(int m, const std::vector<int>& w_water) {
    int time = 0;
    std::priority_queue<int, std::vector<int>, std::greater<int> > minTime;

    // 分配前 m 个任务
    for (int i = 0; i < m && i < w_water.size(); i++) {
        minTime.push(w_water[i]);
    }

    // 分配剩余任务
    for (int i = m; i < w_water.size(); i++) {
        int top = minTime.top();
        minTime.pop();
        top += w_water[i];a
        minTime.push(top);
    }

    // 找出最大完成时间
    while (!minTime.empty()) {
        time = std::max(time, minTime.top());
        minTime.pop();
    }

    return time;
}

int main() {
    int m, n;
    std::vector<int> w_water;

    // 输入机器数量和任务数量
    std::cin >> m >> n;

    // 输入任务时间
    for (int i = 0; i < n; i++) {
        int tmp;
        std::cin >> tmp;
        w_water.push_back(tmp);
    }

    // 计算结果并输出
    int result = water(m, w_water);
    std::cout << result << std::endl;

    return 0;
}

http://www.kler.cn/a/459678.html

相关文章:

  • [Qt] 输入控件 | Line | Text | Combo | Spin | Date | Dial | Slider
  • CSS——2.书写格式一
  • R机器学习:神经网络算法的理解与实操,实例解析
  • Ajax原理-XMLHttpRequest
  • Flink源码编译与运行
  • FastAPI 响应模型与自定义响应
  • 基础数据结构--二叉树
  • 搭建知识中台:大健康零售行业的数字化升级之路
  • Apollo 自动驾驶全景解析
  • keepalived详细笔记
  • PHP语言的软件开发工具
  • 金蝶V10中间件的使用
  • STM32 软件I2C读写
  • 用c++或c 做一个深度遍历的 棋谱树,我用来 做围棋棋谱的教学,要求节省内存、效率高,便于保存(棋谱)和拷贝棋谱
  • Unity 使用UGUI制作卷轴开启关闭效果
  • 【C#】元组
  • 【GO基础学习】gin的使用
  • ArcGIS教程(009):ArcGIS制作校园3D展示图
  • 基于 `android.accessibilityservice` 的 Android 无障碍服务深度解析
  • 20241227通过配置nomodeset参数解决更新grub之后,ubuntu20.04.5无法启动的问题
  • 移动 APP 设计规范参考
  • GXUOJ-算法-第二次作业(矩阵连乘、最长公共子序列、0-1背包问题、带权区间调度)
  • 工厂方法模式详解
  • Redis - 1 ( 7000 字 Redis 入门级教程 )
  • 语言模型在时间序列预测中的作用
  • PHP关键字Self、Static和parent的区别