题目描述
现在有n个容器服务,服务的启动可能有一定的依赖性(有些服务启动没有依赖),其次服务自身启动加载会消耗一些时间。
给你一个 n x n 的二维矩阵useTime,其中
- useTime[i][i]=10 表示服务i自身启动加载需要消耗10s
- useTime[i][j] = 1 表示服务i启动依赖服务j启动完成
- useTime[i][k]=0 表示服务i启动不依赖服务k
其实 0<= i,j,k < n。
服务之间启动没有循环依赖(不会出现环),若想对任意一个服务i进行集成测试(服务i自身也需要加载),求最少需要等待多少时间。
输入描述
第一行输入服务总量 n,
之后的 n 行表示服务启动的依赖关系以及自身启动加载耗时
最后输入 k 表示计算需要等待多少时间后可以对服务 k 进行集成测试
其中 1 <= k <=n,1<=n<=100
输出描述
最少需要等待多少时间(s)后可以对服务 k 进行集成测试
用例
输入 | 3 5 0 0 1 5 0 0 1 5 3 |
输出 | 15 |
说明 | 服务3启动依赖服务2,服务2启动依赖服务1,由于服务1,2,3自身加载需要消耗5s,所以5+5+5=15,需要等待15s后可以对服务3进行集成测试 |
输入 | 3 5 0 0 1 10 1 1 0 11 2 |
输出 | 26 |
说明 | 服务2启动依赖服务1和服务3,服务3启动需要依赖服务1,服务1,2,3自身加载需要消耗5s,10s,11s,所以5+10+11=26s,需要等待26s后可以对服务2进行集成测试。 |
输入 | 4 2 0 0 0 0 3 0 0 1 1 4 0 1 1 1 5 4 |
输出 | 12 |
说明 | 服务3启动依赖服务1和服务2,服务4启动需要依赖服务1,2,3,服务1,2,3自身加载需要消耗2s,3s,4s,5s,所以3+4+5=12s(因为服务1和服务2可以同时启动),要等待12s后可以对服务4进行集成测试。 |
输入 | 5 1 0 0 0 0 0 2 0 0 0 1 1 3 0 0 1 1 0 4 0 0 0 1 1 5 5 |
输出 | 11 |
说明 | 服务3启动依赖服务1和服务2,服务4启动需要依赖服务1,2,服务5启动需要依赖服务3,5,服务1,2,3,4,5自身加载需要消耗1s,2s,3s,4s,5s,所以2+4+5=11s(因为服务1和服务2可以同时启动,服务3和服务4可以同时启动),要等待11s后可以对服务5进行集成测试。 |
解题思路分析
题目要求计算启动某个服务及其依赖的最少时间。可以将这个问题看作一个带权图中的最短路径问题。这里每个服务节点代表一个顶点,依赖关系代表边,边的权重是启动时间。
-
输入描述:
- 第一行:服务总量
n
。 - 接下来的
n
行:表示服务启动的依赖关系及自身启动加载耗时。 - 最后一行:需要计算的服务编号
k
。
- 第一行:服务总量
-
输出描述:
- 最少需要等待多少时间(秒)可以对服务
k
进行集成测试。
- 最少需要等待多少时间(秒)可以对服务
解题步骤:
-
建图:
- 使用一个二维数组
useTime
表示图中的边权重。
- 使用一个二维数组
-
最短路径算法:
- 使用拓扑排序(无环图的特点)来计算从起始服务到目标服务的最短路径。
- 对于每个服务
i
,如果有依赖服务j
,则useTime[i][j]
表示依赖的时间。 - 使用动态规划(DP)来计算从每个服务到目标服务的最短时间。
C++程序实现
#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;
int findMinTime(int n, vector<vector<int>>& useTime, int k) {
vector<int> dp(n, INT_MAX);
dp[k] = 10; // 因为服务k自身启动需要10s
// 拓扑排序计算最长路径
queue<int> q;
vector<int> inDegree(n, 0);
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
if (useTime[i][j] == 1) {
inDegree[j]++;
}
}
}
for (int i = 0; i < n; ++i) {
if (inDegree[i] == 0) {
q.push(i);
if (i != k) {
dp[i] = 0;
}
}
}
while (!q.empty()) {
int u = q.front();
q.pop();
for (int v = 0; v < n; ++v) {
if (useTime[u][v] == 1) {
dp[v] = min(dp[v], dp[u] + 10);
if (--inDegree[v] == 0) {
q.push(v);
}
}
}
}
return dp[k];
}
int main() {
int n;
cin >> n;
vector<vector<int>> useTime(n, vector<int>(n));
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
cin >> useTime[i][j];
}
}
int k;
cin >> k;
k--; // 转换为0索引
int result = findMinTime(n, useTime, k);
cout << result << endl;
return 0;
}
Python程序实现
from collections import deque
import sys
def find_min_time(n, use_time, k):
dp = [sys.maxsize] * n
dp[k] = 10 # 因为服务k自身启动需要10s
# 拓扑排序计算最长路径
q = deque()
in_degree = [0] * n
for i in range(n):
for j in range(n):
if use_time[i][j] == 1:
in_degree[j] += 1
for i in range(n):
if in_degree[i] == 0:
q.append(i)
if i != k:
dp[i] = 0
while q:
u = q.popleft()
for v in range(n):
if use_time[u][v] == 1:
dp[v] = min(dp[v], dp[u] + 10)
in_degree[v] -= 1
if in_degree[v] == 0:
q.append(v)
return dp[k]
# 输入
n = int(input().strip())
use_time = []
for _ in range(n):
use_time.append(list(map(int, input().strip().split())))
k = int(input().strip()) - 1 # 转换为0索引
# 计算并输出结果
result = find_min_time(n, use_time, k)
print(result)
解释
上述代码中,使用拓扑排序来处理服务启动的依赖关系。通过队列和入度数组来管理图的遍历顺序,并使用动态规划数组dp
记录到达每个服务节点的最短时间。通过逐步更新dp
数组,最终得到目标服务的最短启动时间。C++和Python实现的逻辑一致,只是语法有所不同。