题解
题目大意,给定一个无向图,求1到n的次短路,保证1到n有路径,起点终点相同时需要再次回到起点。
使用dijkstra以终点为初始点跑出其它所有节点到终点的最短路径作为A*的h函数值。
以起点为起始点使用A*算法,当第二次到达终点时则为次短路。
AC代码
#include <stdio.h>
#include <bits/stdc++.h>
#define fst first
#define sed second
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const int N = 1e5 + 10;
int n, m;
bool vis[N];
ll dis[N];
struct edge
{
int v, nxt;
ll w;
}e[N * 2];
int h[N], idx;
void AddEdge(int u, int v, ll w)
{
e[++idx] = { v, h[u], w };
h[u] = idx;
}
struct node
{
int v;
ll g, h; //s到v v到t f = g + h
bool operator < (const node &oth) const
{
if (g + h != oth.g + oth.h)
return g + h > oth.g + oth.h;
return g > oth.g;
}
};
void Dijkstra(int src)
{
memset(dis, 0x3f, sizeof(dis));
memset(vis, 0, sizeof(vis));
dis[src] = 0;
priority_queue<node> pq;
pq.push({ src, 0, 0 });
while (!pq.empty())
{
int u = pq.top().v, v;
ll d = pq.top().h, w; pq.pop();
vis[u] = 1;
for (int i = h[u]; i; i = e[i].nxt)
{
v = e[i].v, w = e[i].w;
if (!vis[v] && d + w < dis[v])
dis[v] = d + w, pq.push({ v, 0, dis[v] });
}
}
}
ll AStar(int src, int k)
{
priority_queue<node> pq;
pq.push({ src, 0, 0 });
while (!pq.empty())
{
int u = pq.top().v, v;
ll d = pq.top().g, w; pq.pop();
if (u == n && --k == 0) //是终点且是第k次到
return d;
for (int i = h[u]; i; i = e[i].nxt)
{
v = e[i].v, w = e[i].w;
pq.push({ v, d + w, dis[v] });
}
}
return -1;
}
int main()
{
#ifdef LOCAL
freopen("C:/input.txt", "r", stdin);
#endif
int T;
cin >> T;
while (T--)
{
idx = 0;
memset(h, 0, sizeof(h));
cin >> n >> m;
for (int i = 1; i <= m; ++i)
{
int u, v;
ll w;
scanf("%d%d%lld", &u, &v, &w);
AddEdge(u, v, w);
AddEdge(v, u, w);
}
Dijkstra(n); //求出其它点到终点的最短路
printf("%lld\n", AStar(1, 2));
}
return 0;
}