AI处理器组合
题目描述
某公司研发了一款高性能AI处理器。每台物理设备具备8颗AI处理器,编号分别为0、1、2、3、4、5、6、7。
编号0-3的处理器处于同一个链路中,编号4-7的处理器处于另外一个链路中,不通链路中的处理器不能通信。
如下图所示。现给定服务器可用的处理器编号数组array
,以及任务申请的处理器数量num
,找出符合下列亲和性调度原则的芯片组合。
如果不存在符合要求的组合,则返回空列表。
亲和性调度原则:
- 如果申请处理器个数为1,则选择同一链路,剩余可用的处理器数量为1个的最佳,其次是剩余3个的为次佳,然后是剩余2个,最后是剩余4个。
- 如果申请处理器个数为2,则选择同一链路剩余可用的处理器数量2个的为最佳,其次是剩余4个,最后是剩余3个。
- 如果申请处理器个数为4,则必须选择同一链路剩余可用的处理器数量为4个。
- 如果申请处理器个数为8,则申请节点所有8个处理器。
备注:
- 任务申请的处理器数量只能是1、2、4、8。
- 编号0-3的处理器处于一个链路,编号4-7的处理器处于另外一个链路。
- 处理器编号唯一,且不存在相同编号处理器。
输入描述
输入包含可用的处理器编号数组array
,以及任务申请的处理器数量num
两个部分。
第一行为array
,第二行为num
。
例如:
[0, 1, 4, 5, 6, 7]
1
表示当前编号为0、1、4、5、6、7的处理器可用。任务申请1个处理器。
0
≤
a
r
r
a
y
.
l
e
n
g
t
h
≤
8
0 \leq array.length \leq 8
0≤array.length≤8
0
≤
a
r
r
a
y
[
i
]
≤
7
0 \leq array[i] \leq 7
0≤array[i]≤7
num in [1, 2, 4, 8]
输出描述
输出为组合列表,当array=[0,1,4,5,6,7],num=1
时,输出为[[0], [1]]
。
示例1
输入
[0, 1, 4, 5, 6, 7]
1
输出
[[0], [1]]
说明
根据第一条亲和性调度原则,在剩余两个处理器的链路(0, 1, 2, 3)中选择处理器。
由于只有0和1可用,则返回任意一颗处理器即可。
示例2
输入
[0, 1, 4, 5, 6, 7]
4
输出
[[4, 5, 6, 7]]
说明
根据第三条亲和性调度原则,必须选择同一链路剩余可用的处理器数量为4个的环
解题思路
首先根据任务申请的处理器数量num
分类讨论,根据亲和性调度原则选择符合要求的处理器组合。
- 当
num=1
时,选择同一链路,剩余可用的处理器数量为1个的最佳,其次是剩余3个的为次佳,然后是剩余2个,最后是剩余4个。 - 当
num=2
时,选择同一链路剩余可用的处理器数量2个的为最佳,其次是剩余4个,最后是剩余3个。 - 当
num=4
时,必须选择同一链路剩余可用的处理器数量为4个。 - 当
num=8
时,申请节点所有8个处理器。
需要注意的是,要求选择同一链路的处理器,因此需要先将可用的处理器编号按照链路分别存储。
具体实现时,可以使用回溯算法,在可用的处理器里面进行选择,同时不断更新剩余处理器的数量。
最后,需要对结果去重,因为同一个处理器不能被重复选择。
时间复杂度
根据回溯算法的时间复杂度分析,选择一个处理器的时间复杂度为
O
(
1
)
O(1)
O(1),一共需要选择num
个处理器,因此时间复杂度为
O
(
n
u
m
)
O(num)
O(num)。同时,需要遍历所有可用处理器,时间复杂度为
O
(
2
8
)
O(2^8)
O(28)。因此,总时间复杂度为
O
(
2
8
×
n
u
m
)
O(2^8 \times num)
O(28×num)。
空间复杂度
需要使用递归栈空间,空间复杂度为 O ( n u m ) O(num) O(num)。同时,需要使用集合存储结果,空间复杂度为 O ( 2 8 ) O(2^8) O(28)。因此,总空间复杂度为 O ( 2 8 ) O(2^8) O(28)。
参考解题 Java
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String line = scanner.nextLine();
List<Integer> array = parseList(line); // 解析数组
int num = Integer.parseInt(scanner.nextLine()); // 解析处理器数量
List<List<Integer>> result = new ArrayList<>();
List<List<Integer>> paths = new ArrayList<>();
List<Integer> path = new ArrayList<>();
int[][] links = {{0, 1, 2, 3}, {4, 5, 6, 7}}; // 链路信息
boolean[] visited = new boolean[8];
Arrays.fill(visited, false);
Arrays.sort(array.toArray()); // 排序
dfs(num, links, 0, visited, path, paths); // 深度优先搜索
for (List<Integer> p : paths) {
if (p.size() == num) {
result.add(p);
}
}
printList(result); // 打印结果
}
private static void dfs(int num, int[][] links, int link, boolean[] visited, List<Integer> path, List<List<Integer>> paths) {
if (path.size() == num) { // 如果已经选择了足够数量的处理器
paths.add(new ArrayList<>(path));
return;
}
for (int i = 0; i < links[link].length; i++) { // 在当前链路中选择处理器
int processor = links[link][i];
if (!visited[processor]) {
visited[processor] = true;
path.add(processor);
dfs(num, links, link, visited, path, paths);
path.remove(path.size() - 1);
visited[processor] = false;
}
}
if (path.size() < num) { // 如果当前链路不足,则切换到另一个链路
dfs(num, links, (link + 1) % 2, visited, path, paths);
}
}
private static List<Integer> parseList(String line) {
List<Integer> list = new ArrayList<>();
String[] parts = line.split(",");
for (String part : parts) {
int value = Integer.parseInt(part.trim());
list.add(value);
}
return list;
}
private static void printList(List<List<Integer>> list) {
System.out.print("[");
for (int i = 0; i < list.size(); i++) {
System.out.print("[");
for (int j = 0; j < list.get(i).size(); j++) {
System.out.print(list.get(i).get(j));
if (j < list.get(i).size() - 1) {
System.out.print(", ");
}
}
System.out.print("]");
if (i < list.size() - 1) {
System.out.print(", ");
}
}
System.out.println("]");
}
}