题意:给出一个有向图,求出第k短路,节点可以重复经过。
思路:首先在反向边上进行一次spfa求出任一点至终点的最短距离,将这个距离作为A*搜索的h函数,估价函数f = g + h。注意这题有一个坑点,当起点和终点位于同一位置的时候,没经过任何边不算做一条路径。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<vector>
#include<map>
#include<queue>
#include<stack>
#include<string>
#include<map>
#include<set>
#include<ctime>
#define eps 1e-6
#define LL long long
#define pii pair<int, int>
//#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
const int MAXM = 100100;
const int MAXN = 1010;
const int INF = 0x3f3f3f3f;
struct Edge {
int to, next, w;
} edge[MAXM*2], edge2[MAXM*2];
int head[MAXN], head2[MAXN], tot, tot2;
int n, m;
struct Node {
int f, g, cur;
Node(int f=0, int g=0, int v=0) : f(f), g(g), cur(v) {}
bool operator < (const Node& A) const {
return f==A.f ? g > A.g : f > A.f;
}
};
void addedge(int u,int v,int w) {
edge[tot].to = v;
edge[tot].w = w;
edge[tot].next = head[u];
head[u] = tot++;
}
void addedge2(int u,int v,int w) {
edge2[tot2].to = v;
edge2[tot2].w = w;
edge2[tot2].next = head2[u];
head2[u] = tot2++;
}
bool vis[MAXN]; //在队列标志
int cnt[MAXN]; //每个点的入队列次数
int dist[MAXN];
bool spfa(int start, int n) {
memset(vis, 0, sizeof(vis));
for(int i = 1; i <= n; i++) dist[i] = INF;
vis[start] = 1;
dist[start] = 0;
queue<int> q;
while(!q.empty()) q.pop();
q.push(start);
memset(cnt, 0, sizeof(cnt));
cnt[start] = 1;
while(!q.empty()) {
int u = q.front();
q.pop();
vis[u] = false;
for(int i = head2[u]; i != -1; i = edge2[i].next) {
Edge e = edge2[i];
int v = e.to;
if(dist[v] > dist[u]+e.w) {
dist[v] = dist[u] + e.w;
if(!vis[v]) {
vis[v] = true;
q.push(v);
if(++cnt[v]>n) return false;
}
}
}
}
return true;
}
priority_queue<Node> q;
void init() {
tot = tot2 = 0;
memset(head, -1, sizeof(head));
memset(head2, -1, sizeof(head2));
while(!q.empty()) q.pop();
}
int st, ed, k;
int Astar() {
if(dist[st] == INF) return -1;
if(st == ed) k++;
int cnt = 0;
q.push(Node(dist[st], 0, st));
while(!q.empty()) {
Node t = q.top();
q.pop();
int u = t.cur;
if(u == ed) cnt++;
if(cnt == k) return t.f;
for(int i = head[u]; i != -1; i = edge[i].next) {
int v = edge[i].to, w = edge[i].w;
q.push(Node(t.g+w+dist[v], t.g+w, v));
}
}
return -1;
}
int main() {
//freopen("input.txt", "r", stdin);
while(cin >> n >> m) {
init();
for(int i = 1, u, v, d; i <= m; i++) {
scanf("%d%d%d", &u, &v, &d);
addedge(u, v, d);
addedge2(v, u, d);
}
scanf("%d%d%d", &st, &ed, &k);
spfa(ed, n);
int ans = Astar();
cout << ans << endl;
}
return 0;
}