Description
Input
Output
Sample Input
2 2 1 2 5 2 1 4 1 2 2
Sample Output
14
题目大意:给出一张有向图,求起点S到终点T的第k短路。
我最初的想法是先将环缩点,然后每个点开一个大小为K的堆来记录起点到这里的前K短距离,按着拓扑排序的顺序来递推,用类似归并的方法来统计到每个点的前K段路。但是对于环内部不是很好处理。(其实如果这个图无环的话这样做比本题正解还快。。咳咳)
正解:上午用A*做了八数码,这道题继续A*。用优先队列维护每个点的估值,保证每次搜到终点得到的路径依次是最短,次短。。。估值是A*的精髓,分为g函数和h函数,分别记录从原点来的路径长(已知)和到终点的估值(要求<=实际长度)。在这道题中,g函数记录从原点出发的距离,h函数记录该点到终点的最短路(=实际长度)即可。先边反向跑一次最短路即可获取所有节点的h函数值,然后A*,第K次到达终点即是第K短路。
#include<cstdio> #include<queue> using namespace std; #define MAXM 100005 #define MAXN 1005 const int INF = 1<<28; int N, M, S, T, K; struct Node { int to, len; Node *next; }Edge[MAXM*4], *ecnt = Edge, *adj[MAXN], *radj[MAXN]; void addedge(int a, int b, int c) { ++ecnt; ecnt->to = b; ecnt->len = c; ecnt->next = adj[a]; adj[a] = ecnt; ++ecnt; ecnt->to = a; ecnt->len = c; ecnt->next = radj[b]; radj[b] = ecnt; } struct dijs { int u, dis; dijs () {} dijs (int a,int b) {u=a; dis=b;} bool operator < (const dijs&a) const { return dis > a.dis; } }; int rdis[MAXN]; bool vis[MAXN]; priority_queue<dijs> dij; void rDijkstra() //边反向跑最短路以获取H函数值 { for (int i = 1; i<=1000; ++i) rdis[i] = INF; rdis[T] = 0; dij.push(dijs(T, 0)); dijs t; while (!dij.empty()) { do { if (dij.empty()) return; t = dij.top(); dij.pop(); } while (vis[t.u]); vis[t.u] = 1; for (Node *p = radj[t.u]; p; p=p->next) if (rdis[p->to] > t.dis + p->len) { rdis[p->to] = t.dis + p->len; dij.push(dijs(p->to, rdis[p->to])); } } } struct ss { int u, pre; ss () {} ss (int a, int b) { u=a; pre=b; } bool operator < (const ss&a) const { return pre+rdis[u] > a.pre+rdis[a.u]; //pre是G函数值,rdis是H函数值,根据两个之和判定优先级。 } }; int Tvisn; //第几次到达T点 priority_queue<ss> as; int Astar() { if (S==T) Tvisn = -1; //如果起点终点相等,一开始不算到达终点 as.push(ss(S, 0)); ss t; while (!as.empty()) { t = as.top(); as.pop(); if (t.u == T) { ++Tvisn; if (Tvisn == K) return t.pre; } for (Node *p = adj[t.u]; p; p=p->next) as.push(ss(p->to, t.pre + p->len)); } return -1; } int main() { int i, a, b, c; scanf("%d%d", &N, &M); for (i = 1; i<=M; ++i) { scanf("%d%d%d", &a, &b, &c); addedge(a, b, c); } scanf("%d%d%d", &S, &T, &K); rDijkstra(); printf("%d\n", Astar()); return 0; }