第一道第K短路的题目 QAQ
拿裸的DIJKSTRA + 不断扩展的A* 给2000MS过了
题意:大意是 有N个station 要求从s点到t点 的第k短路 (不过我看题意说的好像是从t到s 可能是出题人写错了)
从这题中还真的学到了很多
1.第k短路的算法 A* 还有用边表实现dij
(注:以下部份资料来源于网上)
所谓A*就是启发是搜索 说白了就是给搜索一个顺序使得搜索更加合理减少无谓的搜索. 如何来确定搜索的顺序?..也就是用一个值来表示 这个值为f[n]..每次搜索取f[x]最小的拓展 那么这个f[n]=h[n]+g[n]
其中f(n) 是节点n的估价函数,g(n)是在状态空间中从初始节点到n节点的实际代价,h(n)是从n到目标节点最佳路径的估计代价。在这里主要是h(n)体现了搜索的启发信息,因为g(n)是已知的。如果说详细 点,g(n)代表了搜索的广度的优先趋势。但是当h(n) >> g(n)时,可以省略g(n),而提高效率。
A*算法的估价函数可表示为:
f’(n) = g’(n) + h’(n)
这里,f’(n)是估价函数,g’(n)是起点到终点的最短路径值,h’(n)是n到目标的最短路经的启发值。由 于这个f’(n)其实是无法预先知道的,所以我们用前面的估价函数f(n)做近似。g(n)代替g’(n),但 g(n)>=g’(n) 才可(大多数情况下都是满足的,可以不用考虑),h(n)代替h’(n),但h(n)<=h’(n)才可(这一点特别的重 要)。可以证明应用这样的估价函数是可以找到最短路径的,也就是可采纳的。我们说应用这种估价函数的 最好优先算法就是
1 #include <stdio.h> 2 #include <string.h> 3 #include <stdlib.h> 4 #include <math.h> 5 #include <iostream> 6 #include <stack> 7 #include <queue> 8 #include <algorithm> 9 10 #define ll long long 11 using namespace std; 12 const int INF = 0x3f3f3f3f; 13 const int MAXN = 1111; 14 15 struct vertex{ 16 int sum, h, pos; 17 bool operator < (vertex a) const{ 18 return a.sum + a.h < sum + h; 19 } 20 }; 21 struct sc{ 22 int u, v, w, next; 23 }line1[MAXN*MAXN],line2[MAXN*MAXN]; 24 25 int link1[MAXN],link2[MAXN],h[MAXN],times[1001]; 26 int n, m, s, e, k; 27 bool vis[MAXN]; 28 priority_queue <vertex> que; 29 30 void init(){ 31 memset(link1, 0, sizeof(link1)); 32 memset(link2, 0, sizeof(link2)); 33 memset(vis,0,sizeof(vis)); 34 memset(h,0x3f,sizeof(h));//h函数初始值为最大 35 while (!que.empty()) que.pop(); 36 memset(times,0,sizeof(times)); 37 } 38 39 void djikstra(){ 40 int i,k,p; 41 h[e] = 0; 42 for (p = 1; p <= n; ++p){ 43 k = 0; 44 for (i = 1; i <= n; ++i) 45 if (!vis[i] && (!k||h[i]<h[k])) k = i; 46 vis[k] = true; 47 k = link2[k]; 48 while (k){ 49 if (h[line2[k].v] > h[line2[k].u] + line2[k].w) 50 h[line2[k].v] = h[line2[k].u] + line2[k].w; 51 k = line2[k].next; 52 } 53 } 54 } 55 56 int Astar(){ 57 int t; 58 vertex g,temp; 59 g.pos = s; 60 g.sum = 0; 61 g.h = h[s]; 62 que.push(g); 63 64 if (s==e) ++k; 65 while (!que.empty()){ 66 g = que.top();//每次取估价函数值最小的节点 67 que.pop(); 68 ++times[g.pos]; 69 if (times[g.pos] == k && g.pos == e) return g.sum + g.h; 70 if (times[g.pos] > k) continue; 71 72 t = link1[g.pos]; 73 while (t){//扩展,并把其加入优先队列即openlist 74 temp.sum = g.sum + line1[t].w; 75 temp.h = h[line1[t].v]; 76 temp.pos = line1[t].v; 77 que.push(temp); 78 t = line1[t].next; 79 } 80 } 81 return -1; 82 } 83 84 int main(){ 85 int i, j; 86 while(cin >> n >> m){ 87 init(); 88 for (i = 1; i <= m; ++i){ 89 cin >> line1[i].u >> line1[i].v >> line1[i].w; 90 line1[i].next = link1[line1[i].u];//记录与节点u有直接边的节点 91 link1[line1[i].u] = i; 92 93 line2[i].u = line1[i].v; 94 line2[i].v = line1[i].u; 95 line2[i].w = line1[i].w; 96 line2[i].next = link2[line2[i].u]; 97 link2[line2[i].u] = i; 98 } 99 cin >> s >> e >> k; 100 djikstra(); 101 cout << Astar() << endl; 102 } 103 return 0; 104 }
POJ 2449 求第K短路
时间: 2024-10-13 10:56:40