题意:给你一个图以及起点和终点,求起点到终点的第k短路的大小。
思路:先用迪杰斯特拉求出每个点到终点的最短路,然后用A*算法,令f(x)为每点到终点的距离,将f(x)附加到每条边的边权上,再利用优先队列对最小的进行扩展,直接暴力搜相邻边,则第k个从优先队列中出来的就是正解。思路很明了,代码写起来很复杂。。。
#include<cstdio> #include<cstring> #include<algorithm> #include<vector> #include<map> #include<queue> #define ll long long using namespace std; const int inf = 0x3f3f3f3f; const int maxn = 1005; struct edge { int v, w, nxt; }G[100005], G2[100005]; int tot, pre[maxn], t2, p2[maxn]; struct node { int v, d; friend bool operator < (node a, node b) { if(a.d!=b.d) return a.d>b.d; return a.v>b.v; } }; int n, m, k, dist[maxn]; bool vis[maxn]; void dijkstra(int s) { memset(dist, 0x3f, sizeof(dist)); memset(vis, 0, sizeof(vis)); dist[s] = 0; priority_queue<node> que; node y; y.v=s; y.d=0; que.push(y); while (!que.empty()) { node p = que.top(); que.pop(); if (vis[p.v]) { continue; } vis[p.v] = true; for (int i = p2[p.v]; ~i; i = G2[i].nxt) { int v = G2[i].v, w = G2[i].w; if (!vis[v] && p.d + w < dist[v]) { dist[v] = p.d + w; node x; x.v=v; x.d=dist[v]; que.push(x); } } } } struct point { int v, h, g; friend bool operator < (point a, point b) { return a.h+a.g>b.h+b.g; } }; int times[maxn]; int Astar(int s, int e) { if(dist[s]==inf) { return -1; } memset(times, 0, sizeof(times)); priority_queue<point> Q; point y; y.v=s; y.g=0; y.h=0; Q.push(y); while (!Q.empty()) { point p = Q.top(); Q.pop(); ++times[p.v]; if (times[p.v] == k && p.v == e) { return p.h + p.g; } if (times[p.v] > k) { continue; } for (int i = pre[p.v]; ~i; i = G[i].nxt) { point x; x.v=G[i].v; x.h=p.h+G[i].w; x.g=dist[G[i].v]; Q.push(x); } } return -1; } int main() { int u, v, w, s, e; scanf("%d%d", &n, &m); tot = t2 = 0; memset(pre, -1, sizeof(pre)); memset(p2, -1, sizeof(p2)); while(m--) { scanf("%d%d%d", &u, &v, &w); G[tot].v = v; G[tot].w = w; G[tot].nxt = pre[u]; pre[u] = tot++; G2[t2].v = u; G2[t2].w = w; G2[t2].nxt = p2[v]; p2[v] = t2++; } scanf("%d%d%d", &s, &e, &k); if (s == e) { k++; } dijkstra(e); printf("%d\n", Astar(s, e)); return 0; }