[模板] k短路

简介

Dijkstra最短路+A*搜索.

先逆向求所有点到终点的最短路 \(dis[i]\).

定义估价函数 \(f[i] = d[i] + dis[i]\), 其中 \(d[i]\) 表示当前起点到 \(i\) 点的路径长度.

与Dijkstra算法类似, 将 \(f[i]\) 放到堆中, 每次求出 \(f[i]\) 最小的节点 \(u\) , 维护相邻节点 \(v\)\(d[v]\)\(f[v]\).

当第 \(k\)\(u\) 为终点, \(f[u]\) 即为起点到重点的第 \(k\) 短路.

代码

//the nth point is departure, 1st is destination

const int nsz=1050,msz=10050;
const ll ninf=1e16;
int n,m,k;
struct te{int t,pr,v;}edge[msz*2];
int hd[nsz],pe=1;
void adde(int f,int t,int v){edge[++pe]=(te){t,hd[f],v};hd[f]=pe;}
void addsg(int f,int t,int v){adde(f,t,v);adde(t,f,-1);}

ll dis[nsz],vi[nsz];
struct tnd{ll p,d;};
bool operator<(tnd l,tnd r){return l.d>r.d;}
priority_queue<tnd> pq;
void dij(int f){
    rep(i,1,n)dis[i]=ninf;
    dis[f]=0;
    pq.push((tnd){f,0});
    while(!pq.empty()){
        int u=pq.top().p;pq.pop();
        if(vi[u])continue;
        for(int i=hd[u],v=edge[i].t;i;i=edge[i].pr,v=edge[i].t){
            if(edge[i].v!=-1)continue;//inv edge
            if(dis[v]>dis[u]+edge[i^1].v)dis[v]=dis[u]+edge[i^1].v,pq.push((tnd){v,dis[v]});
        }
    }
//  rep(i,1,n)cout<<dis[i]<<'\n';
}
ll ans[nsz],pa=0;
void astar(){
    if(dis[n]>=ninf)return;
    pq.push((tnd){n,dis[n]});
    while(!pq.empty()){
        ll u=pq.top().p,d=pq.top().d;pq.pop();
        if(u==1){
            ans[++pa]=d;
            if(pa==k)break;
            continue;
        }
        for(int i=hd[u],v=edge[i].t;i;i=edge[i].pr,v=edge[i].t){
            if(edge[i].v==-1)continue;
            pq.push((tnd){v,d-dis[u]+dis[v]+edge[i].v});
        }
    }
}

//use
    dij(1);
    while(!pq.empty())pq.pop();
    astar();
}

猜你喜欢

转载自www.cnblogs.com/ubospica/p/9879307.html
今日推荐