K短路

次短路

目前知道的方法有: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();
}
posted @ 2020-08-15 09:07  DSHUAIB  阅读(81)  评论(0)    收藏  举报