题目:https://www.acwing.com/problem/content/description/180/
给定一张N个点(编号1,2…N),M条边的有向图,求从起点S到终点T的第K短路的长度,路径允许重复经过点或边。
注意: 每条最短路中至少要包含一条边。
输入格式
第一行包含两个整数N和M。
接下来M行,每行包含三个整数A,B和L,表示点A与点B之间存在有向边,且边长为L。
最后一行包含三个整数S,T和K,分别表示起点S,终点T和第K短路。
输出格式
输出占一行,包含一个整数,表示第K短路的长度,如果第K短路不存在,则输出“-1”。
数据范围
1≤S,T≤N≤1000
0≤M≤1e5
1≤K≤1000
1≤L≤100
输入样例:
2 2
1 2 5
2 1 4
1 2 2
输出样例:
14
题解:首先是启发式函数,根据f(x) <= g(x) 的函数理论(f(x)是启发式函数,g(x)为实际最短距离),我们考虑,对终点反向建图得到dis[x],也就是作为每个点到终点的f(x),然后由于是k短路,我们每次更新完每个点,直接放入队列(只需要判断这个点拿出来的次数是否小于k即可),另外由于需要的结点的真实距离(距离起点的真实距离)较多,我们考虑将它一起存入队列。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,b,a) for(int i=b;i>=a;i--)
#define x first
#define y second
#define Mst(a,b) memset(a,b,sizeof(a))
typedef pair<int,int> PII;
typedef pair<int,PII> PIII;
const int N = 1005,M = 2e5+5;
int head[N],nxt[M],e[M],w[M],n,m,tot,dis[N],cnt[N],head1[N];
bool st[N];
void add(int head[],int a,int b,int c) {
e[tot] = b;
w[tot] = c;
nxt[tot] = head[a];
head[a] = tot++;
}
void dijkstra(int x) {
priority_queue<PII,vector<PII>,greater<PII> > q;
memset(dis,0x3f,sizeof(dis));
dis[x] = 0; q.push({0,x});
while(q.size()) {
auto t = q.top();
q.pop();
if(st[t.y]) continue;
st[t.y] = true;
for(int i=head1[t.y];i != -1;i = nxt[i]) {
int j = e[i];
if(dis[j] > dis[t.y] + w[i]) {
dis[j] = dis[t.y] + w[i];
q.push({dis[j],j});
}
}
}
}
int A_star(int x,int y,int k) {
priority_queue<PIII,vector<PIII>,greater<PIII> > q;
q.push({dis[x],{0,x}});
while(q.size()) {
auto t = q.top();
q.pop();
cnt[t.y.y]++;
if(t.y.y == y && cnt[t.y.y] == k) return t.y.x;
for(int i=head[t.y.y];i != -1;i = nxt[i]) {
int j = e[i];
if(cnt[j] < k)
q.push({t.y.x + dis[j] + w[i],{t.y.x + w[i],j}});
}
}
return -1;
}
int main() {
cin >> n >> m;
int a,b,c,s,t,k;
Mst(head,-1);
Mst(head1,-1);
rep(i,1,m) {
cin >> a >> b >> c;
add(head,a,b,c);
add(head1,b,a,c);
}
cin >> s >> t >> k;
if(s == t) k++;
dijkstra(t);
cout << A_star(s,t,k);
return 0;
}