阿里3.26笔试第二题——酒店的平均距离
阿里3.26日笔试第二题。我没有参加笔试,但是听人说是2020年威海站的题,就按照威海站做的。时间复杂度最高达到O(n^4),欢迎有好的优化思路的小伙伴在评论区留言,欢迎收藏与转发。
package Algorithms.AL.AL010;
import java.util.Scanner;
/**
* 题目描述
* 三名理论计算机科学家计划前往威海旅行。 但是,他们无法就住宿达成共识,因为有些人喜欢某些酒店,
* 而另一些人则喜欢其他酒店。 他们决定晚上住在不同的旅馆里,第二天在一个旅馆见面。
* 他们见面的酒店不一定是他们入住的酒店之一。
* 每对酒店之间都有一条特定长度的道路,每位理论计算机科学家都会在旅行开始之前准备好候选酒店列表。
* 当他们到达威海时,他们每个人都会从候选酒店列表中统一独立地选择一家酒店。
* 而且,他们将在一家酒店见面,以使他们的路线总长度最小化。
* 作为理论计算机科学小组的成员,您能说出他们的路线的预期总长度吗?
*
* 输入描述
* 输入的第一行包含一个整数 n(1≤ n ≤200000),表***海的酒店数量。
* 接下来 n-1 行中的每行都包含三个整数 u,v,w(1≤u,v≤n,u≠v,1≤w≤1000),
* 表示长度为 w 的道路,连接编号为 u 和 v 的旅馆。
* 保证每对酒店之间都有一条独特的道路。
* 输入的最后三行指定候选酒店列表,每位理论计算机科学家一行。
* 每行有一个整数 m(1≤ m ≤n)和 m 个不同的整数 a1,a2,⋯,am(1≤ ai ≤n),这意味着候选酒店列表为编号为 a1,a2,⋯,的酒店。
*
* 输出描述
* 输出所有情况下最短总路程的平均值
*
* 示例1
* 输入
* 3
* 1 2 1
* 2 3 2
* 1 1
* 1 2
* 1 3
* 输出
* 3
*
* 示例2
* 输入
* 5
* 1 2 3
* 1 3 5
* 2 4 7
* 2 5 11
* 3 2 4 5
* 4 1 2 3 5
* 2 1 3
* 输出
* 13.958333333333
*
*/
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
while (scanner.hasNext()) {
// 获取酒店数量
int n = scanner.nextInt();
// 构建酒店之间直接距离矩阵
int[][] distances = new int[n][n];
// 将直接距离初始化为 Integer.MAX_VALUE,表示各个酒店之间没有连接
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
distances[i][j] = Integer.MAX_VALUE;
}
}
// 同一酒店与自己的距离当然为 0
for (int i = 0; i < n; i++) {
distances[i][i] = 0;
}
// 接下来 n-1 行,获取每两个酒店 u 和 v 之间的直接距离 w
for (int i = 0; i < n-1; i++) {
int u = scanner.nextInt()-1;
int v = scanner.nextInt()-1;
int w = scanner.nextInt();
distances[u][v] = distances[v][u] = w;
}
// 利用 Floyed 算法计算每两个酒店之间的最短距离
for (int t = 0; t < n; t++) {
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (distances[i][t] < Integer.MAX_VALUE && distances[t][j] < Integer.MAX_VALUE
&& distances[i][t] + distances[t][j] < distances[i][j]) {
distances[i][j] = distances[i][t] + distances[t][j];
}
}
}
}
// 接下来获取三名科学家每个人喜欢的酒店编号
// 第一名科学家喜欢的酒店数量
int num1 = scanner.nextInt();
// 第一名科学家喜欢的酒店编号
int[] favorite1 = new int[num1];
for (int i = 0; i < num1; i++) {
favorite1[i] = scanner.nextInt()-1;
}
// 第二名科学家喜欢的酒店数量
int num2 = scanner.nextInt();
// 第二名科学家喜欢的酒店编号
int[] favorite2 = new int[num2];
for (int i = 0; i < num2; i++) {
favorite2[i] = scanner.nextInt()-1;
}
// 第三名科学家喜欢的酒店数量
int num3 = scanner.nextInt();
// 第三名科学家喜欢的酒店编号
int[] favorite3 = new int[num3];
for (int i = 0; i < num3; i++) {
favorite3[i] = scanner.nextInt()-1;
}
// 三名科学家一共有 num1*num2*num3 种不同组合
int nums = num1*num2*num3;
// 设置总路径
int sum = 0;
// 获取每种情况下的最短路径
for (int i = 0; i < num1; i++) {
for (int j = 0; j < num2; j++) {
for (int k = 0; k < num3; k++) {
// 计算最小值
int min = Integer.MAX_VALUE;
for (int v = 0; v < n; v++) {
min = Math.min(min, distances[favorite1[i]][v] + distances[favorite2[j]][v] + distances[favorite3[k]][v]);
}
sum += min;
}
}
}
// 输出统计结果
System.out.println(sum*1.0/nums);
}
}
}

