看到了一个讲解k短路的感觉不错。。。。。
对于A* ,估价函数 = 当前值+当前位置到终点的距离,即 F(p)=g(p)+h(p),每次扩展估价函数值中最小的一个。对于k短路来说,g(p)为当前从s到p所走的长度,h(p)为从p到 t 的最短路的长度,则F(p)的意义就是从s按照当前路径走到 p 后要走到终点 t 一共至少要走多远。也就是说我们每次的扩展都是有方向的扩展,这样就可以提高求解速度和降低扩展的状态数目。为了加速计算,h(p)需要从A*搜索之前进行预处理,只要将原图的所有边反向,再从终点 t 做一次单源最短路径就可以得到每个点的h(p)了。
还有就是这个题意说是t到s的k短路。。但样例给的是s到t的所以就在写程序的时候求s到t的就可以了。。囧。。
#include<cstdio> #include<iostream> #include<cstring> #include<queue> using namespace std; #define inf 1<<30 #define cc(m,v) memset(m,v,sizeof(m)) #define M 100005 struct node { int v, g, f, next; // f=g+h bool operator<(const node & t) const { if (t.f == f) return t.g < g; return t.f<f; } } edge[M], edge1[M]; int head[1005], p, head1[1005], n, dis[1005]; void spfa(int s) { int u, v, i, j, cot[1005]; queue<int> q; bool vis[1005]; for (i = 0; i <= n; i++) dis[i] = inf, cot[i]=0, vis[i]=0; vis[s] = 1, dis[s] = 0, q.push(s); while (!q.empty()) { u = q.front(),q.pop(), vis[u] = 0, cot[u]++; if(cot[u]>=n) return ; for (j = head1[u]; j != -1; j = edge1[j].next) if (dis[v=edge1[j].v] > dis[u] + edge1[j].g) { dis[v]=dis[u]+edge1[j].g; if(!vis[v]) vis[v] = 1, q.push(v); } } } int a_star(int s, int t, int k) { int cnt = 0, i; struct node e, ne; priority_queue<node> que; if (s == t) k++; if (dis[s] == inf) return -1; e.v = s, e.g = 0, e.f = e.g + dis[e.v]; que.push(e); while (!que.empty()) { e = que.top(), que.pop(); if (e.v == t) { cnt++; if (cnt == k) return e.g; } for (i = head[e.v]; i != -1; i = edge[i].next) { ne.v = edge[i].v, ne.g = e.g + edge[i].g; ne.f = ne.g + dis[ne.v], que.push(ne); } } return -1; } void ainit() { p = 0, cc(head, -1), cc(head1, -1); } void addedge(int u, int v, int w) { edge[p].v = v, edge[p].g = w, edge[p].next = head[u], head[u] = p; edge1[p].v = u, edge1[p].g = w, edge1[p].next = head1[v], head1[v] = p++; } int main() { int s, m, t, u, v, w, i, k; while (scanf("%d%d", &n, &m) != -1) { ainit(); for (i = 1; i <= m; i++) { scanf("%d%d%d", &u, &v, &w); addedge(u, v, w); } scanf("%d%d%d", &s, &t, &k); spfa(t); printf("%d\n", a_star(s, t, k)); } return 0; }