#P2295. 第2题-服务器健康巡检
-
1000ms
Tried: 248
Accepted: 92
Difficulty: 5
所属公司 :
华为
时间 :2024年9月19日-留学生
-
算法标签>贪心算法
第2题-服务器健康巡检
题面解释:
为了最小化检查数据中心服务器的时间,我们可以采取以下策略:首先,使用行检查,能够同时检查多行服务器,耗时1秒;然后,使用列检查,单列检查耗时2秒。我们需要读取机架数量及每个机架的服务器数量,并找出最大的服务器数量来决定检查方式。优先进行行检查,尽可能多地覆盖服务器,再用列检查完成剩余的检查。代码实现通过标记已检查的行和计算总耗时来得到最终结果。通过这种方式,我们可以高效地确保所有服务器都得到检查,达到最小的时间消耗。
思路:贪心+递归
对一个数组arr,对min(arr)进行一个行操作。剩下的区间递归进行。直到l = r , 进行列操作 具体细节看代码注释
题解
本题旨在计算对一组服务器高度数组进行检查所需的最小代价。代价的计算方式分为两部分:行操作和列操作。具体来说,我们将根据数组中的最小值执行行操作,并在处理完所有行之后,对单个服务器进行列操作。
-
行操作: 如果区间内有多个服务器的高度大于当前最小值,我们将这些服务器的高度减少到最小值,这一过程的代价为1秒。此时,我们会递归地处理剩余的区间。
-
列操作: 当区间缩小至仅包含一个服务器时,必须进行列操作,此时的代价为2秒。
通过这样的递归操作,我们可以有效地计算出整个数组的最小检查代价。算法的核心在于寻找当前区间的最小值,并在此基础上递归处理,直至每个服务器都被检查完毕。
代码分析
- 输入部分: 首先读取服务器数量和高度。
- 递归函数
minCost:- 基本条件: 处理了左边界大于右边界和只包含一个元素的特殊情况。
- 最小值计算: 遍历当前区间以找到最小的服务器高度。
- 行操作: 使用循环遍历区间,处理所有大于最小值的服务器,进行递归调用。
- 输出部分: 打印计算得到的最小代价。
代码
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;
}
OJ会员可以通过点击题目上方《已通过》查看其他通过代码来学习。
题目内容
在一个未来的超级数据中心,有一排存放服务器的阵列,阵列由一列一列的机架组成,机架的每一行可以存放一个服务器,每列架子的服务器都是自底向上依次摆放,摆放的个数是随机且大于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