题意整理
- 给定一张带权无向图,图中任意两点间有且仅有一条路径。
- 求从任意点出发,访问完所有节点后,所经过边的权值和的最小值。
方法一(dfs)
1.解题思路
要想边权值最小,所走的路径中必定包含了最长(边权值最大)无重复节点的路径,只要求出这个路径权值和,用所有路径权值和的两倍减去最大路径权值和,即得到所经过边的权值和的最小值。
- 首先初始化邻接表,遍历点对集合Edge,计算所有边长度的两倍。
- 先从1号节点进入递归,通过递归找到当前节点所能到达的最远节点,跟新最远节点的规则是路径权值和大于之前的权值和。
- 然后再从最远节点处继续进入递归体,寻找最大路径权值和。
- 找到之后,用所有边长度的两倍减去这个权值和。
由于测试数据较大,栈深度会溢出,通过自定义栈深度的方式可以避免。
动图展示:
2.代码实现
import java.util.*;
/*
* public class Point {
* int x;
* int y;
* }
*/
public class Solution {
/**
* 最短距离
* @param n int整型
* @param Edge Point类一维数组
* @param val int整型一维数组
* @return long长整型
*/
//邻接表
List<List<int[]>> graph;
//结果变量
long res=0;
//记录最远节点
long far=0;
//记录无重复最长路径
long max=0;
public long solve (int n, Point[] Edge, int[] val) {
//初始化邻接表
graph=new ArrayList<>();
for(int i=0;i<n;i++){
graph.add(new ArrayList<>());
}
//计算所有路径和的两倍,即res的值
for(int i=0;i<Edge.length;i++){
res+=2*val[i];
graph.get(Edge[i].x-1).add(new int[]{Edge[i].y-1,val[i]});
graph.get(Edge[i].y-1).add(new int[]{Edge[i].x-1,val[i]});
}
//从1号点开始递归
try{
Thread t=new Thread(null,()->{
dfs(0,-1,0);
},"自定义栈深度",1<<30);
t.start();
t.join();
}
catch(Exception e){}
max=0;
//找到最远点后,从当前点递归
try{
Thread t=new Thread(null,()->{
dfs(far,-1,0);
},"自定义栈深度",1<<30);
t.start();
t.join();
}
catch(Exception e){}
return res-max;
}
//深度优先搜索
private void dfs(long cur,long pre,long dist){
//跟新当前最长路径以及最远点
if(dist>max){
max=dist;
far=cur;
}
for(int[] sub:graph.get((int)cur)){
//如果没有走回头路,则将子节点放入队列
if(sub[0]!=(int)pre){
dfs(sub[0],cur,dist+sub[1]);
}
}
}
} 3.复杂度分析
- 时间复杂度:最坏情况下,递归栈的深度为n,所以时间复杂度是
。
- 空间复杂度:最坏情况下邻接表的大小为
,所以空间复杂度为
。
方法二(bfs)
1.解题思路
- 首先初始化邻接表,遍历点对集合Edge,计算所有边长度的两倍。
- 将1号节点入队,找到当前节点所能到达的最远节点,跟新最远节点的规则是路径权值和大于之前的权值和。如果没有走回头路,将所有可能的子节点入队。
- 找到最远节点后,继续将最远节点入队,找出最大权值和。
- 找到之后,用所有边长度的两倍减去这个权值和。
2.代码实现
import java.util.*;
/*
* public class Point {
* int x;
* int y;
* }
*/
public class Solution {
/**
* 最短距离
* @param n int整型
* @param Edge Point类一维数组
* @param val int整型一维数组
* @return long长整型
*/
//邻接表
List<List<int[]>> graph;
//结果变量
long res=0;
//记录最远节点
long far=0;
//记录无重复最长路径
long max=0;
public long solve (int n, Point[] Edge, int[] val) {
//初始化邻接表
graph=new ArrayList<>();
for(int i=0;i<n;i++){
graph.add(new ArrayList<>());
}
for(int i=0;i<Edge.length;i++){
res+=2*val[i];
graph.get(Edge[i].x-1).add(new int[]{Edge[i].y-1,val[i]});
graph.get(Edge[i].y-1).add(new int[]{Edge[i].x-1,val[i]});
}
//初始化队列
Queue<long[] > queue=new LinkedList<>();
//从1号点开始找
bfs(queue,0,-1,0);
max=0;
//找到最远点后,从当前点继续找
bfs(queue,far,-1,0);
return res-max;
}
//广度优先搜索
private void bfs(Queue<long[] > queue,long cur,long pre,long dist){
//加入起始节点到队列
queue.offer(new long[]{cur,pre,dist});
while(!queue.isEmpty()){
//取出当前节点信息
long[] node=queue.poll();
cur=node[0];
pre=node[1];
dist=node[2];
//如果大于max,则跟新最远距离以及最远节点
if(dist>max){
max=dist;
far=cur;
}
for(int[] sub:graph.get((int)cur)){
//如果没有走回头路,则将子节点放入队列
if(sub[0]!=(int)pre){
queue.offer(new long[]{sub[0],cur,dist+sub[1]});
}
}
}
}
} 3.复杂度分析
- 时间复杂度:最坏情况下,需要将n个节点入队,所以时间复杂度是
。
- 空间复杂度:最坏情况下邻接表的大小为
,所以空间复杂度为
。

京公网安备 11010502036488号