试题 算法训练 逗志芃的暴走 java实现

问题描述
  逗志芃是有妹子的现充,但是有时候妹子就是烦恼。因为逗志芃太逗了,所以这段时间妹子对逗志芃发动了技能无理取闹,妹子要去玩很多的景点。由于逗志芃之前抽机花费了太多的时间,不久以后又要微积分考试了,所以现在被妹子搞成暴走状态了。但是妹子永远是上帝,所以逗志芃只能带妹子出去玩,不过为了节约时间,他希望找到一条花费时间最少的一次性游览线路。
输入格式
  第一行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代码应该可以优化,两个循环可以写成一个,不过要思考结束条件,就不想了,嘿嘿。

猜你喜欢

转载自blog.csdn.net/adminguojieBin/article/details/123162645