dijkstra算法可求单源最短问题,解说可查看blog:https://blog.youkuaiyun.com/yalishadaa/article/details/55827681
在CCF中的交通规划一题中遇到,我用的做法是0分(但是我找不出来问题,虽然说用临界矩阵存数组会过大可能会导致内存溢出,但是不可能10分都没有,而且测试数据也过了),思想就是用dijkstra计算最短路径,并且在沿途中纪录下得到的远点与每个点的最短路径中的点与点之间的最短距离,最后加起来等于所求。
题目为:http://118.190.20.162/view.page?gpid=T44
我的做法:
package csp.csp20169;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Scanner;
public class ReTrafficPlan {
int[] dist; // 保存v0到点i的距离
int[][] arr; // 保存图
boolean[] s; // true表示已求出最短路径的点,false为未球场
int[] prev;// i的前驱节点,本题中不需要
int v0;// 源点
int n;
int[] costto; //连同该点所需要的代价
public static void main(String[] args){
new ReTrafficPlan().run();
}
public void run(){
Scanner scanner = new Scanner(System.in);
n = scanner.nextInt();
int m = scanner.nextInt();
arr = new int[n][n];
s = new boolean[n];
costto = new int[n];
prev = new int[n];
dist = new int[n];
v0 = 0;
for(int i = 0;i < n;i++){
for(int j = 0;j < n;j++){
arr[i][j] = Integer.MAX_VALUE;
arr[j][i] = Integer.MAX_VALUE;
}
}
for(int i = 0;i < m;i++){
int a = scanner.nextInt()-1;
int b = scanner.nextInt()-1;
int cost = scanner.nextInt();
arr[a][b] = cost;
arr[b][a] = cost;
}
int res = 0;
dijstra();
for(int i = 0;i < n;i++){
// System.out.print( " pre " + i + " " + prev[i] + " ");
// if(i != v0)res += arr[prev[i]][i];
res += costto[i];
}
// System.out.println(Arrays.toString(costto));
System.out.print(res);
}
public void dijstra(){
// 1.初始化所有数据
for(int i = 0;i < n;i++){
if(arr[v0][i] != 0){
dist[i] = arr[v0][0];
prev[i] = v0;
}else {
dist[i] = Integer.MAX_VALUE;
prev[i] = -1;
}
costto[i] = Integer.MAX_VALUE;
}
s[v0] = true;
dist[v0] = 0;
costto[v0] = 0;
// costto[v0] = 0;
// 求解过程
for(int i = 0;i < n;i++){
int minDist = Integer.MAX_VALUE;
int u = v0;
// 找到未求出最短路径的集合U中距离v0最近的点u
for(int j = 0;j < n;j++){
if(!s[j] && dist[j] < minDist){
minDist = dist[j];
u = j;
}
}
// 把u加进S集合中
s[u] = true;
dist[u] = minDist;
// 以u为中间点,修改U中的点到v0的距离(若变得更短,则更新)
for(int j = 0;j < n;j++){
if(!s[j]){
int newDis = dist[u] + arr[u][j];
if(dist[j] > newDis){
dist[j] = dist[u] + arr[u][j];
prev[j] = u;
costto[j] = arr[u][j];
}
if(newDis == dist[j]){
costto[j] = Math.min(costto[j], arr[u][j]);
}
}
}
}
}
}
另一个系统认可的做法(100):
该做法也是用了dijstra方法,它用优先队列来存放未找到最短路径的点。
package csp.csp20169;
import java.util.LinkedList;
import java.util.PriorityQueue;
import java.util.Scanner;
public class ReTrafficPlan3 {
public class Node implements Comparable<Node>{
// 源点到index的距离
int index;
int cost;
public Node(int index,int cost){
this.index = index;
this.cost = cost;
}
@Override
public int compareTo(Node o) {
// TODO Auto-generated method stub
return this.cost - o.cost;
}
}
public class Edge{
// 边的第二个点
int second;
int cost;
public Edge(int second,int cost){
this.second = second;
this.cost = cost;
}
}
PriorityQueue<Node> queue;
LinkedList<Edge>[] list;
int[] disv;
boolean[] s; // true表示已求出最短路径的点,false为未球场
int[] prev;// i的前驱节点
int v0;// 源点
int n;
int[] costto; //连同该点所需要的代价
public static void main(String[] args){
new ReTrafficPlan3().run();
}
public void run(){
Scanner scanner = new Scanner(System.in);
n = scanner.nextInt();
int m = scanner.nextInt();
s = new boolean[n];
costto = new int[n];
prev = new int[n];
list = new LinkedList[n];
queue = new PriorityQueue<>();
v0 = 0;
disv = new int[n];
for(int i = 0;i < list.length;i++){
list[i] = new LinkedList<>();
disv[i] = Integer.MAX_VALUE;
costto[i] = Integer.MAX_VALUE;
}
for(int i = 0;i < m;i++){
int a = scanner.nextInt()-1;
int b = scanner.nextInt()-1;
int cost = scanner.nextInt();
list[a].add(new Edge(b,cost));
list[b].add(new Edge(a, cost));
}
disv[v0] = 0;
costto[v0] = 0;
int res = 0;
queue.add(new Node(v0, 0));
dijstra();
for(int i = 1;i < n;i++){
res += costto[i];
}
// System.out.println(Arrays.toString(costto));
System.out.print(res);
}
public void dijstra(){
while(!queue.isEmpty()){
// 每次都得到未找到最短路径的离源点最近的点
Node node = queue.poll();
int curP = node.index;
s[curP] = true;
for(int i = 0;i < list[curP].size();i++){
Edge edge = list[curP].get(i);
int nextP = edge.second;
if(!s[nextP]){
int cost = edge.cost;
// 若找到以curP为中间点,与源点连接的路径变短的点nextP,则更新dist[nextP]
int newDis = cost + disv[curP];
if(disv[nextP] > newDis){
disv[nextP] = newDis;
costto[nextP] = cost;
// 更新完把该点放进未找到最短路径的集合进行遍历,放在这里
// queue.add(new Node(nextP, disv[nextP]));
}
if(newDis == disv[nextP]){
costto[nextP] = Math.min(costto[nextP], cost);
}
// 若此条语句放在这里也可,但是会运行超时,因为有很多多余的节点要遍历
queue.add(new Node(nextP, disv[nextP]));
}
}
}
}
}