题目描述
现有一个共
n
个顶点、m
条边的有向无环图(假设顶点编号为从0
到n-1
),求图的所有路径中边权之和的最大值(不固定起点和终点)
输入描述
第一行两个整数
n、m(1≤n≤100,0≤m≤n(n−1))
,分别表示顶点数、边数;接下来
m
行,每行三个整数u、v、w(0≤u≤n−1,0≤v≤n−1,u≠v,1≤w≤100)
,表示一条边的起点和终点的编号及边权。数据保证不会有重边
输出描述
输出一个整数,表示路径上边权之和的最大值
样例
输入
6 7
0 1 1
0 2 2
1 3 3
1 4 4
2 4 2
3 5 2
4 5 3
输出
8
思路分析
- 题目不限制起点终点,因此根据贪心的原则,有路径就应该试着走一走,同时应该把每个顶点都当作起点试一遍
- 如果我们能够知道由当前顶点
i
出发的最大权值之和,再通过比较各个权值之和选出最大值maxVal
,就可以作为我们的答案。因此问题关键在于:如何记录由当前顶点i
出发的最大权值之和?由此我们可以考虑使用动态规划 - 设置
g[n][n]
用来存放顶点和边的关系,设置dp
数组,其中dp[i]
代表由当前顶点i
出发所能得到的最大权值之和 - 假设当前顶点
i
到顶点j
之间有路径,那么由dp[i]
的取值无非只有两种:dp[i]
本身,即当前知道的i
出发能够得到的权值之和,但是由于我们对dp
的处理还不完全,因此此时的权值之和不一定是最大的dp[j] + g[i][j]
,即顶点i
到顶点j
的权重加上从j
出发能够得到的权值之和- 选择其中最大的作为
dp[i]
真正的值【此时i
是固定的,j
是变化的】
- 此处可以做一个优化,即当
dp[i]>0
时直接返回dp[i]
,因为此时说明dp[i]
已经被处理过,内部存储的就是从i
点出发的最大值,不需要重复处理 - 最后可以得到整体被处理好的数组
dp
,其中的最大值就是我们的答案
代码实现
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int m = scanner.nextInt();
// 存放地图
int g[][] = new int[n][n];
// dp[i]代表从 i 出发能够得到的最大权重之和
int dp[] = new int[n];
// 对图进行初始化
for (int i = 0; i < m; i++) {
int u = scanner.nextInt();
int v = scanner.nextInt();
int w = scanner.nextInt();
g[u][v] = w;
}
int maxVal = 0;
for (int i = 0; i < n; i++) {
maxVal = Math.max(maxVal, getDAGMaxLength(g, dp, i, n));
}
System.out.println(maxVal);
}
// 返回从 i 出发的有向无环图最大权值之和路径
public static int getDAGMaxLength(int g[][], int dp[], int i, int n) {
// 说明 i 点已经处理过,不需要重复计算
if (dp[i] > 0) {
return dp[i];
}
for (int j = 0; j < n; j++) {
// i 到 j 有路可走
if (g[i][j] > 0) {
// 看看从 j 出发的最大权值之和 + 当前顶点 i 到 j 的权重是否大于直接从 i 出发的最大权值之和
dp[i] = Math.max(dp[i], getDAGMaxLength(g, dp, j, n) + g[i][j]);
}
}
return dp[i];
}
}