#P14056. 【贪心7】服务器健康巡检
-
ID: 2157
Tried: 429
Accepted: 124
Difficulty: 5
【贪心7】服务器健康巡检
【贪心7】服务器健康巡检
在数据中心服务器的检查过程中,时间是一个非常关键的因素。为了尽量减少检查的总时间,我们可以采取一种优化策略:首先,通过行检查同时检查多行服务器,耗时为1秒;然后,使用列检查,每列检查耗时2秒。我们的目标是最小化总的检查时间,并且通过合理的选择行检查和列检查的顺序来实现。
解题思路
这个问题可以通过贪心算法和递归来高效地求解。具体步骤如下:
- 行检查优先:我们可以优先选择进行行检查,即在区间内将所有大于当前最小值的服务器高度调整为最小值。每一次行检查的代价为1秒。
为什么行检查优先?因为行检查至少能完全检查1列(每次行检查都取本区间的最小值作为它的高度),而列检查只能完全检查1列,同时行检查耗时比列检查少。
-
列检查:当区间只剩下一个服务器时,必须进行列检查,这时的代价为2秒。
-
递归过程:我们从一个区间开始,选择最小值进行行检查,然后递归地处理剩余的区间。直到所有区间都被检查完毕,每个区间都要计算其最小代价。
代码分析
-
输入:首先读取服务器的数量和每台服务器的高度。
-
递归函数
minCost
:这个函数接收一个区间[l, r]
,计算这个区间内所有服务器的最小检查代价。- 基本情况:如果区间为空或只包含一个服务器,直接返回0或2秒。
- 查找最小值:对当前区间内的所有服务器进行遍历,找到最小高度。
- 行操作:通过行检查将所有大于最小值的服务器高度减少至最小值,并递归处理剩余的区间。
-
输出:计算并输出从第1台到第n台服务器的最小检查代价。
代码实现
java
import java.util.Scanner;
public class Main {
static int[] h;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
h = new int[n + 1]; // 1-based indexing
for (int i = 1; i <= n; i++) {
h[i] = sc.nextInt();
}
// 计算并输出最小操作代价
System.out.println(minCost(1, n));
}
// 计算区间 [l, r] 的最小代价
static int minCost(int l, int r) {
if (l > r) {
return 0;
}
if (l == r) {
return 2; // 单个服务器默认为单列操作
}
int minH = Integer.MAX_VALUE;
for (int i = l; i <= r; i++) {
minH = Math.min(minH, h[i]);
}
// 行操作
int cost1 = 1;
int i = l;
while (i <= r) {
if (h[i] > minH) {
int start = i;
while (i <= r && h[i] > minH) {
i++;
}
cost1 += minCost(start, i - 1);
} else {
i++;
}
}
return cost1;
}
}
python
import sys
# 递归深度设置为1000000
sys.setrecursionlimit(1000000)
n_and_rest = sys.stdin.read().split()
n = int(n_and_rest[0])
h = list(map(int, n_and_rest[1:n+1]))
h = [0] + h # 1-based indexing
def min_cost(l, r):
if l > r:
# 空区间的操作代价为0
return 0
if l == r:
# 一个服务器的操作默认为单列操作
return 2
min_h = min(h[l:r+1])
# 操作1: 用行操作,找到<不是最小高度>的连续区间
cost1 = 1
i = l
while i <= r:
# 找到连续区间
if h[i] > min_h:
# 找到连续区间的起始位置
start = i
# 找到连续区间的终止位置
while i <= r and h[i] > min_h:
i += 1
# 递归计算连续区间的最小代价
cost1 += min_cost(start, i - 1)
else:
i += 1
return cost1
total_min_cost = min_cost(1, n)
print(total_min_cost)
cpp
#include <iostream>
#include <vector>
#include <algorithm>
#include <climits>
using namespace std;
vector<int> h; // 服务器高度数组
// 计算区间 [l, r] 的最小代价
int minCost(int l, int r) {
// 如果左边界大于右边界,返回0(无操作)
if (l > r) {
return 0;
}
// 如果区间只包含一个服务器,返回列操作的代价2
if (l == r) {
return 2;
}
// 找到当前区间的最小高度
int minH = INT_MAX;
for (int i = l; i <= r; i++) {
minH = min(minH, h[i]); // 更新当前最小高度
}
// 进行行操作,初始代价为1秒
int cost1 = 1;
int i = l; // 从左边界开始遍历
while (i <= r) {
// 如果当前服务器的高度大于最小值
if (h[i] > minH) {
int start = i; // 记录当前区间的起始位置
// 向右移动,直到找到不再大于最小值的服务器
while (i <= r && h[i] > minH) {
i++;
}
// 对于当前找到的区间,递归计算其代价
cost1 += minCost(start, i - 1);
} else {
// 如果当前服务器高度不大于最小值,继续向右移动
i++;
}
}
return cost1; // 返回当前区间的总代价
}
int main() {
int n;
cin >> n; // 输入服务器数量
h.resize(n + 1); // 调整数组大小以便使用1-based索引
for (int i = 1; i <= n; i++) {
cin >> h[i]; // 输入每个服务器的高度
}
cout << minCost(1, n) << endl; // 输出从1到n的最小检查代价
return 0;
}
本题为2024年9月19日华为留学生机考原题
华为机考的介绍点击这里
题目内容
在一个未来的超级数据中心,有一排存放服务器的阵列,阵列由一列一列的机架组成,机架的每一行可以存放一个服务器,每列架子的服务器都是自底向上依次摆放,摆放的个数是随机且大于0的。现在有一个运维机器人用来检查服务器健康状态,机器人有行列2种检查模式:
- 行检查支持多行服务器一起检查,检查时间为1秒。
- 列检查仅支持单列服务器检查,检查时间为2秒。
约束说明:
- 允许在同一个服务器检查多次,但同一次行、列检查模式的服务器必须为连续的一段。
- 单独的一个服务器检查,默认采用列检查方式,检查时间为2秒。
- 行、列检查时间跟检查列的服务器数量无关,仅与检查模式相关。
请问机器人最少要花费多少时间才能检查完整个数据中心的服务器。
输入描述
入参分为两行输入:
- 第一行为机架的数量n。
- 第二行n个整数rack1,...,rackn空格隔开表示每个机架摆放服务器的数量。
输出描述
检查完所有服务器最少需要的花费时间
样例1
输入
3
5 5 5
输出
1
说明
采用行检查,因为多行可以一起检查,所以1次行扫描就检查完了,耗时1s
样例2
输入
5
2 2 1 2 1
输出
4
说明
第一次采用行检查,覆盖1~5列的第1行服务器,耗时1s,第二次采用行检查,覆盖1~2列的第2行服务器,耗时1s,第三次采用列检查,覆盖第4列第2行的服务器,耗时2s,总计耗时4s
样例3
输入
5
7 4 3 3 5
输出
6
说明
第一次采用行检查,覆盖1~5列的1~3行服务器,耗时1s,第二次采用行检查,覆盖1~2列的第4行服务器,耗时1s,第三次采用列检查,覆盖第1列的5~7行的服务器,耗时2s,第四次采用列检查,覆盖第5列的4~5行的服务器,耗时2s,总计耗时6s