华为OD-100-流水线(C C++ Java Py JS)

题目描述

一个工厂有 m 条流水线,来并行完成 n 个独立的作业,该工厂设置了一个调度系统,在安排作业时,总是优先执行处理时间最短的作业。

现给定流水线个数 m,需要完成的作业数 n,每个作业的处理时间分别为 t1,t2tn 。请你编程计算处理完所有作业的耗时为多少?

n > m 时,首先处理时间短的 m 个作业进入流水线,其他的等待,当某个作业完成时,依次从剩余作业中取处理时间最短的进入处理。

输入描述

第一行为 2个整数 (采用空格分隔),分别表示流水线个数 m 和作业数 n;0 < m,n < 100

第二行输入 n 个整数 (采用空格分隔) ,表示每个作业的处理时长 t1,t2tn。0 < t1,t2...tn < 100。

注:保证输入都是合法的。

输出描述

输出处理完所有作业的总时长。

示例1

输入

3 5
8 4 3 2 10

输出

13

说明

  1. 先安排 2、3、4 的 3 个作业;
  2. 第一条流水线先完成作业,然后调度剩余时间最短的作业 8;
  3. 第二条流水线完成作业,然后调度剩余时间最短的作业 10;
  4. 总耗时就是第二条流水线完成作业的时间 13 (3 + 10 = 13)。

解析

本题考查贪心算法。

首先,我们可以将所有作业按照处理时间升序,这样我们顺序取出的作业,必然是剩余作业中处理时间最短的。

然后,我们顺序地取出作业,并将作业依次加入到 1~ m 序号的流水线中

假设作业处理时间 t1 ≤ t2 ≤ t3 … ≤ tn,那么依次加入到流水线的情况如下
在这里插入图片描述
其中 t1 最小,因此序号 1 的流水线首先空闲出来,然后加入 t[m+1] 作业
在这里插入图片描述
此时思考一个问题:下一个率先空闲出来的流水线是哪个?
因为,t[1] ≤ t[2] ≤ t[3] … ≤ t[m] ≤ t[m+1]
所以,t[2] - t[1] ≤ t[3] - t[1] ≤ … ≤ t[m] - t[1] < t[m+1]
进而推得:后续流水线会依次按照序号2、序号3、…序号m、序号1空闲出来

通过上面推理,我们可以知道,如果我们顺序地取出(按照处理时间升序后)作业,并依次加入到 1 ~ m 序号的流水线,那么流水线也会按照 1 ~ m 的序号顺序依次空闲出来。如下图,是 m 条流水线累计处理的作业情况

在这里插入图片描述

由于流水线是依次 1~m 空闲出来的,因此,最后一个作业落在哪条流水线上,则对应流水线就是最后完成的。

由于作业是按顺序依次加入到 1 ~ m 流水线的,因此,最后完成的流水线上的处理过的作业倒序依次是 t[n],t[n-m],t[n-2m],…,我们只需要累加这些作业时间,即为题解。

源码实现

C

#include <stdio.h>
#include <stdlib.h>

#define MAX_N 100

int cmp(const void *a, const void *b) {
    return *((int *) a) - *((int *) b);
}

int main() {
    int m, n;
    scanf("%d %d", &m, &n);

    int t[MAX_N];
    for (int i = 0; i < n; i++) {
        scanf("%d", &t[i]);
    }

    qsort(t, n, sizeof(t[0]), cmp);

    int result = 0;
    for (int i = n - 1; i >= 0; i -= m) {
        result += t[i];
    }

    printf("%d", result);

    return 0;
}

C++

#include <bits/stdc++.h>

using namespace std;

int main() {
    int m, n;
    cin >> m >> n;

    vector<int> t(n);
    for (int i = 0; i < n; i++) {
        cin >> t[i];
    }

    sort(t.begin(), t.end());

    int result = 0;
    for (int i = n - 1; i >= 0; i -= m) {
        result += t[i];
    }

    cout << result;

    return 0;
}

Java

import java.util.Arrays;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        int m = sc.nextInt();
        int n = sc.nextInt();

        int[] t = new int[n];
        for (int i = 0; i < n; i++) {
            t[i] = sc.nextInt();
        }

        Arrays.sort(t);

        int result = 0;
        for (int i = n - 1; i >= 0; i -= m) {
            result += t[i];
        }

        System.out.println(result);
    }
}

Python

if __name__ == '__main__':
    m, n = map(int, input().split())
    t = list(map(int, input().split()))

    t.sort()

    result = 0
    for i in range(n - 1, -1, -m):
        result += t[i]

    print(result)

JavaScript

const rl = require("readline").createInterface({ input: process.stdin });
var iter = rl[Symbol.asyncIterator]();
const readline = async () => (await iter.next()).value;

void (async function () {
  const [m, n] = (await readline()).split(" ").map(Number);
  const t = (await readline()).split(" ").map(Number);

  t.sort((a, b) => a - b);

  let result = 0;
  for (let i = n - 1; i >= 0; i -= m) {
    result += t[i];
  }

  console.log(result);
})();
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码到自然成

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值