一. 原题链接:http://poj.org/problem?id=2449
二. 题目大意:给一个有向图,给出S(起点)和T(终点),让你求第K短路。
三. 思路:启发式搜索A*算法+SPFA求最短路做为H[]估值函数。
先建立原图的反向图,用SPFA算法,求出图中各点到源点的最短路径。
A*算法有2个函数G(x)和H(x),G(x)表示从起点到该点x的路径长度,H(x)表示从该点到终点的最短路径。
A*算法步骤:
1.计算起点的G(x)(也就是0)和H(x),将其加入优先级队列(优先级队列优先级为G(x)+H(x),小的话先出。)。
2.在优先级队列不为空时,一直弹出队首,对于每个队首元素,进行如下操作:
遍历与其连接的每个点,更新每个店的G(x)和H(x),将其压入优先级队列。
3.当第k次寻找到终点,G(x)+H(x)的值就是第K短路的路径长度。
4.若未到第k次,队列就为空,说明不存在第K短路,输出-1。
利用优先队列维护,相当于A*算法中所谓开启列表,而这题没有关闭列表,因为要搜多条路径。
其实这题的A*算法说白了,就是在BFS的基础上,队列使用优先队列。再加上寻找到第K次才退出,总体难度还是不难,但是由于太久没做还有强行用Java的原因,做了一个晚上加上一个早上。
四.注意点:
1. 有重边,不要考虑邻接矩阵。
2. S==T的时候,先k++。因为当S==T的时候,要算先走一次。
五.代码:
//POJ2449 import java.util.*; class Main { final static int MAX_SIZE = 1010; final static int INF = 0x3f3f3f3f; static class Node{ public int v; public int weight; } static List<Node> Graph[] = new ArrayList[MAX_SIZE]; static List<Node> reGraph[] = new ArrayList[MAX_SIZE]; static int nodeNum; static int edgeNum; static int k; static int[] SPFA(int start, int end){ int dist[] = new int[nodeNum+1]; boolean inQue[] = new boolean[nodeNum+1]; Queue<Integer> que = new LinkedList<Integer>(); int i, cur; for (i = 0; i < nodeNum+1; i++){ dist[i] = INF; inQue[i] = false; } dist[start] = 0; que.offer(start); inQue[start] = true; while (!que.isEmpty()) { cur = que.poll(); inQue[cur] = false; Iterator<Node> it = reGraph[cur].iterator(); while (it.hasNext()){ Node node = it.next(); int v = node.v; int weight = node.weight; if (dist[v] > dist[cur] + weight){ dist[v] = dist[cur] + weight; if (!inQue[v]){ inQue[v] = true; que.offer(v); } } } } return dist; } static int AStar(int start, int end, int []H){ class Point{ public int id; public int h; public int g; } Comparator<Point> order = new Comparator<Point>(){ public int compare(Point a, Point b){ int fa = a.g + a.h; int fb = b.g + b.h; return fa>fb? 1:(fa==fb?0:-1); } }; Queue<Point> que = new PriorityQueue<Point>(nodeNum, order); Point cur = new Point(); cur.g = 0; cur.h = H[start]; cur.id = start; que.offer(cur); int cnt = 0; while(!que.isEmpty()){ cur = que.poll(); if (cur.id == end){ cnt++; if (cnt == k){ return cur.g + cur.h; } } Iterator<Node> it = Graph[cur.id].iterator(); while(it.hasNext()){ Node tmp = it.next(); int v = tmp.v; int weight = tmp.weight; Point nextP = new Point(); nextP.g = cur.g + weight; nextP.h = H[v]; nextP.id = v; que.offer(nextP); } } return -1; } public static void main(String[] args) { Scanner in = new Scanner(System.in); nodeNum = in.nextInt(); edgeNum = in.nextInt(); int u, v, w, i; for (i = 1; i <= nodeNum; i++) Graph[i] = new ArrayList<Node>(); for (i = 1; i <= nodeNum; i++) reGraph[i] = new ArrayList<Node>(); for (i = 0; i < edgeNum; i++){ u = in.nextInt(); v = in.nextInt(); w = in.nextInt(); Node newNode = new Node(); newNode.v = v; newNode.weight = w; Graph[u].add(newNode); //反向图 Node newNodeForRe = new Node(); newNodeForRe.v = u; newNodeForRe.weight = w; reGraph[v].add(newNodeForRe); } int start, end; start = in.nextInt(); end = in.nextInt(); k = in.nextInt(); int dist[] = SPFA(end, start); if (start == end) k++; System.out.println(AStar(start, end, dist)); in.close(); } }