aStar算法求第k短路
A*的概念主意在于估计函数,f(n)=g(n)+h(n),f(n)是估计函数,g(n)是n节点的当前代价,h(n)是n节点的估计代价;而实际中,存在最优的估计函数f'(n)=g'(n)+h'(n),那么显然我们在A*的估计中,h(n)<=h'(n),否则你将搜不到最优解;(g(n)>=g'(n)我还不怎么清楚为什么啊,大多数情况是g(n)=g'(n),这个可以不用管吧。。)
求s->t的第k短路,
dist[x]为x->t的最短路 (这个只要反向建边,然后一次spfa,求出任意点到t点的距离即可
那么点x的g(x)=到达当前点的花费
h(x) = dist[x] , 可以知道h(x)=h'(x),所以可以保证搜到最优解。
每次出出队列的都是当前f(x)最小的点,
所以如果点x出队列, 那么就cnt[x]++,
当cnt[x]==k时,那么当前的f(x)就是第k短路,因为第一次出队列时,肯定是最短路上的点,第二次是次短路上的点,第k次,自然就是第k短路上的点了。
1 #pragma warning(disable:4996) 2 #pragma comment(linker, "/STACK:1024000000,1024000000") 3 #include <stdio.h> 4 #include <string.h> 5 #include <time.h> 6 #include <math.h> 7 #include <map> 8 #include <set> 9 #include <queue> 10 #include <stack> 11 #include <vector> 12 #include <bitset> 13 #include <algorithm> 14 #include <iostream> 15 #include <string> 16 #include <functional> 17 #include <iostream> 18 typedef __int64 LL; 19 const int INF = 1 << 30; 20 21 /* 22 */ 23 const int N = 1000 + 10; 24 struct Node 25 { 26 int from, to, dis, next; 27 }g[N*100]; 28 int head[N], e; 29 int dist[N]; 30 bool vis[N]; 31 int cnt[N]; 32 void addEdge(int u, int v, int dis) 33 { 34 g[e].from = u; 35 g[e].to = v; 36 g[e].dis = dis; 37 g[e].next = head[u]; 38 head[u] = e++; 39 } 40 41 void spfa(int src, int n) 42 { 43 for (int i = 1;i <= n;++i) 44 dist[i] = INF; 45 std::queue<int> q; 46 q.push(src); 47 dist[src] = 0; 48 while (!q.empty()) 49 { 50 int u = q.front(); q.pop(); 51 vis[u] = false; 52 for (int i = head[u];i + 1;i = g[i].next) 53 { 54 int v = g[i].to; 55 if (dist[v] > dist[u] + g[i].dis) 56 { 57 dist[v] = dist[u] + g[i].dis; 58 if (!vis[v]) 59 { 60 vis[v] = true; 61 q.push(v); 62 } 63 } 64 } 65 } 66 } 67 void init() 68 { 69 e = 0; 70 memset(head, -1, sizeof(head)); 71 } 72 void reverse() 73 { 74 memset(head, -1, sizeof(head)); 75 int te = e; 76 e = 0; 77 for (int i = 0;i < te;++i) 78 addEdge(g[i].to, g[i].from, g[i].dis); 79 } 80 struct Node2 81 { 82 int to; 83 int g; 84 bool operator<(const Node2&rhs)const 85 { 86 return g + dist[to] > rhs.g + dist[rhs.to]; 87 } 88 }; 89 /* 90 因为每次出队列的都是最短的, 所以该点是第几次出队列,就表示是该点到终点的第k短路 91 */ 92 int aStar(int src, int des, int k) 93 { 94 std::priority_queue<Node2> q; 95 Node2 cur, tmp; 96 cur.to = src; 97 cur.g = 0; 98 q.push(cur); 99 while (!q.empty()) 100 { 101 cur = q.top(); q.pop(); 102 int u = cur.to; 103 cnt[u]++; 104 if (cnt[u] > k) continue; 105 if (cnt[u] == k) 106 return cur.g + dist[u]; 107 for (int i = head[u];i + 1;i = g[i].next) 108 { 109 int v = g[i].to; 110 tmp.to = v; 111 tmp.g = cur.g + g[i].dis; 112 q.push(tmp); 113 } 114 } 115 return -1; 116 } 117 int main() 118 { 119 int n, m, src, des, k; 120 while (scanf("%d%d", &n, &m) != EOF) 121 { 122 init(); 123 int u, v, dis; 124 for (int i = 1;i <= m;++i) 125 { 126 scanf("%d%d%d", &u, &v, &dis); 127 addEdge(v, u, dis); 128 } 129 scanf("%d%d%d", &src, &des, &k); 130 spfa(des, n); 131 reverse(); 132 if (src == des)k++;//如果起点等于终点,那么最短路其实是什么都不走 133 int ans = aStar(src, des, k); 134 printf("%d\n", ans); 135 } 136 return 0; 137 }