次短路

目前知道的方法有:1.跑一遍最短路,一次枚举删边 2.在跑最短路时同时记录最短路与次短路 3.起点和终点分别跑一次最短路,枚举边来替换最短路上的边

例题P1491 集合位置

#include<cstdio>
#include<cmath>
#include<queue>
#include<cstring>
using namespace std;
typedef pair<double, int> PDI;
const int INF = 1e9;
const int N = 100005;
int x[N], y[N], head[N], ver[N], net[N], tot, path[N], vis[N], n, m;
double edge[N], dist[N];
void add(int a,int b,double c)
{
net[++tot] = head[a];
head[a] = tot;
edge[tot] = c;
ver[tot] = b;
}

void Dij(int a,int b)
{
memset(vis, 0, sizeof(vis));
for (int i = 1; i <= n;i++)
dist[i] = INF;
priority_queue<PDI, vector<PDI>, greater<PDI> > q;
dist[1] = 0;
q.push({0, 1});
while(!q.empty())
{
int v = q.top().second;
q.pop();
if(vis[v])
continue;
vis[v] = 1;
for (int i = head[v]; i;i=net[i])
{
int v1 = ver[i];
if((a==v&&b==v1)||(a==v1&&b==v))//是否被删除
continue;
if(dist[v1]>dist[v]+edge[i])
{
if(a==-1&&b==-1)//记录最短路上的路径
path[v1] = v;
dist[v1] = dist[v] + edge[i];
q.push({dist[v1], v1});
}
}
}
}

int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n;i++)
scanf("%d%d", &x[i], &y[i]);
for (int i = 1; i<=m;i++)
{
int p, q;
scanf("%d%d", &p, &q);
double dis = sqrt((x[p] - x[q]) * (x[p] - x[q]) + (y[p] - y[q]) * (y[p] - y[q]));
add(p, q, dis);
add(q, p, dis);
}
Dij(-1, -1);//先跑一次最短路
int v1 = n;
double ans = INF;
while(path[v1])//依次枚举删除的边
{
Dij(v1, path[v1]);
ans = min(dist[n], ans);//求出删除边过后所得的最短距离的最小值,即次短路
v1 = path[v1];
}
if(ans==INF)
printf("-1");
else
printf("%.2f",ans) ;
}

A*算法求K短路

先跑一遍最短路,求出估价距离,第K次出队的即为第K短路

#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
const int N=500005;
typedef pair<int, int> PII;
typedef pair<int, PII> PIII;
int head1[N], head2[N], net[N], edge[N], ver[N], tot;
int dist[N], vis[N], n, m, k, a, b, ans[N];

void add(int h[],int a,int b,int c)
{
net[++tot]=h[a];
h[a]=tot;
edge[tot]=c;
ver[tot]=b;
}

void astar()
{
int t=0;
priority_queue<PIII, vector<PIII>, greater<PIII> > q;
q.push({ dist[a], { 0, a } });
while(!q.empty())
{
int v1=q.top().second.second;
int distence=q.top().second.first;
//printf("%d%d\n", v1,distence);
q.pop();
if (distence+dist[v1]>=0x3f3f3f3f)
continue;
if (v1==b)
{
t++;
if (t==k)
{
printf("%d",distence);
return;
}
}
for(int i=head1[v1];i;i=net[i])
{
int v2=ver[i];
q.push({ distence+dist[v2]+edge[i], { distence+edge[i], v2 } });
}
}
printf("-1");
}

void dij()
{
memset(dist, 0x3f, sizeof(dist));
memset(vis, 0, sizeof(vis));
priority_queue <PII, vector<PII>, greater<PII> > q;
q.push({ 0, b });
dist[b]=0;
while(!q.empty())
{
int v1=q.top().second;

q.pop();
if (vis[v1])
continue;
vis[v1]=1;
for(int i=head2[v1];i;i=net[i])
{
int v2=ver[i];
if(dist[v2]>dist[v1]+edge[i])
{
dist[v2]=dist[v1]+edge[i];
q.push({ dist[v2], v2 });
}
}
}
}

int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
int u, v, l;
scanf("%d%d%d",&u,&v,&l);
add(head1, u, v, l);
add(head2, v, u, l);
}
scanf("%d%d%d",&a,&b,&k);
if (a==b)
k++;
dij();
astar();
}