问题描述
逗志芃是有妹子的现充,但是有时候妹子就是烦恼。因为逗志芃太逗了,所以这段时间妹子对逗志芃发动了技能无理取闹,妹子要去玩很多的景点。由于逗志芃之前抽机花费了太多的时间,不久以后又要微积分考试了,所以现在被妹子搞成暴走状态了。但是妹子永远是上帝,所以逗志芃只能带妹子出去玩,不过为了节约时间,他希望找到一条花费时间最少的一次性游览线路。
输入格式
第一行1个数n,表示逗志芃所在的城市有多少个景点,接下来是一个n*n的矩阵。a(i,j)表示i号景点到j号景点的路上花费的时间是多少。
接下来是一个数m,表示逗志芃妹子要去去的景点数目。由于妹子在无理取闹,所以可能会有重复的景点,不过只要去一次就可以了。接下来是m个数,就是妹子要去的景点编号。
输出格式
一个数,最少的花费时间。
样例输入
3
0 1 2
1 0 3
2 3 0
3
2 3 1
样例输出
3
数据规模和约定
0<n<=30,0<m<=20,时间<=1000000
解题思路:利用Floyd算法将点与点之间的最短路径算出来,然后再对要去的景点dfs计算最优解(遍历完后的最优解是不会走重复的点的)
import java.util.Scanner;
//有重复的点
public class Main {
static int n, m;// n代表n行n列 m代表旅游景点个数
static int[][] map = new int[31][31];// 存储给定的景点之间的距离
static int[] vis = new int[31];// 存储景点的状态,0是没有走过的,1是已经走过
static int[] b = new int[21];// m个输入要去的景点
static int ans = Integer.MAX_VALUE;// 最终最短路径长度
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
n = scanner.nextInt();
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
map[i][j] = scanner.nextInt();
}
}
floyd();// 进行floyd计算点与点之间的最短距离
m = scanner.nextInt();
for (int i = 1; i <= m; i++) {
b[i] = scanner.nextInt();
}
// 进行dfs搜索
for (int i = 1; i <= m; i++) {// 遍历要去的景点
vis[b[i]] = 1;// 将第一个点状态置1
dfs(b[i], 0);
vis[b[i]] = 0;// 恢复状态
}
System.out.println(ans);
}
// 利用Floyd算法得出点到点之间的最优解
public static void floyd() {
for (int k = 1; k <= n; k++) {// 中间点
for (int i = 1; i <= n; i++) {// 起始点
for (int j = 1; j <= n; j++) {// 终点
map[i][j] = Math.min(map[i][j], map[i][k] + map[k][j]);
}
}
}
}
public static void dfs(int u, int length) {
boolean flag = true;// 结束的标志
for (int i = 1; i <= m; i++) {// 遍历所有要去的景点的状态,如果都是1说明已经都走过了,就结束。
if (vis[b[i]] == 0) {// 找到还有没走的景点
flag = false;// 修改结束标志
break;// 跳出循环
}
}
if (flag) {// 结束则判断之前的路径和当前路径的大小,取较小值
ans = Math.min(ans, length);
return;
}
for (int i = 1; i <= m; i++) {// 没有结束则遍历要去的景点
if (vis[b[i]] == 0 && length + map[u][b[i]] <= ans) {// 判断景点是否去过,到下一个景点的距离长度小于当前最佳路径的值,才考虑走这个点
vis[b[i]] = 1;// 将景点状态置1
dfs(b[i], length + map[u][b[i]]);// 寻找下一个点
vis[b[i]] = 0;// 恢复景点状态
}
}
}
}
提交结果:
dfs代码应该可以优化,两个循环可以写成一个,不过要思考结束条件,就不想了,嘿嘿。