K短路

104 篇文章 0 订阅
46 篇文章 0 订阅

SPFA算法+A*启发式搜索。

1.考虑建立反图,然后跑最短路算法得到以tt为根的最短路径生成树。

2.A*启发式搜索计算第K最短路的长度。

注意:1.最多求出经由的K条路,若大于K条路,就不再往下走了

           2.如果起点终点相同,则K+1

以POJ 2449为模板的S->T的K短路。

#include<cstdio>
#include<queue>
#include<vector>

using namespace std;

#define INF 0x3f3f3f3f
const int N=1100;

typedef struct nnn{         //定义优先队列的元素类型
    int F,G,s;              //对应节点s,起点至该节点的距离G,经过s的路长F
    friend bool operator < (nnn a,nnn b){
        return a.F>b.F;
    }
}PATH;

typedef struct nn{          //邻接表节点的结构定义。
    int v,w;                //邻接点V,边长W。
}node;

vector<node> map[N],tmap[N];//邻接表map,辅助邻接表tmap,
int H[N];                   //反向距离表,即end至节点i的距离为H[i]


void findH(int s){          //SPFA算法计算s可达的每个点的距离值H[]
    queue<int> q;
    int vis[N]={0};         //设所有节点非队列元素标志
    q.push(s);vis[s]=1;H[s]=0;//s进入队列,距离值为0
    while(!q.empty()){
        s=q.front();
        q.pop();
        vis[s]=0;
        int m=tmap[s].size();
        for(int i=0;i<m;i++){
            int j=tmap[s][i].v;
            if(H[j]>tmap[s][i].w+H[s]){
                H[j]=tmap[s][i].w+H[s];
                if(!vis[j]) vis[j]=1,q.push(j);
            }
        }
    }
}

int Astar(int st,int en,int K){//计算st至en的第k短的路径长度
    priority_queue<PATH> q;
    PATH p,tp;                  //被扩展的元素p,被扩展的新元素tp
    int k[N]={0};               //计算节点经过的次数
    findH(en);                  //计算反向距离表H
    if(H[st]==(int)INF) return -1;//en不能到达st
    p.s=st;p.G=0;p.F=H[st];
    q.push(p);
    while(!q.empty()){
        p=q.top();q.pop();
        k[p.s]++;
        if(k[p.s]>K) continue;
        if(p.s==en&&k[p.s]==K) return p.F;
        int m=map[p.s].size();
        for(int i=0;i<m;i++){
            int j=map[p.s][i].v;
            if(H[j]!=(int)INF){
                tp.G=p.G+map[p.s][i].w;
                tp.F=H[j]+tp.G;
                tp.s=j;
                q.push(tp);
            }
        }
    }
    return -1;
}

int main(){
    int n,m,S,T,K,a,b,t;
    node p;
    scanf("%d%d",&n,&m);
    for(int i=1;i<n;i++){
        map[i].clear();
        tmap[i].clear();
        H[i]=INF;
    }
    while(m--){
        scanf("%d%d%d",&a,&b,&t);
        p.v=b;p.w=t;map[a].push_back(p);
        p.v=a;tmap[b].push_back(p);
    }
    scanf("%d%d%d",&S,&T,&K);
    if(S==T) K++;
    printf("%d\n",Astar(S,T,K));
    return 0;
}
#include<iostream>
#include<cstdio>
#include<queue>
#include<vector>

using namespace std;

const int inf=0x3f3f3f3f;
const int N=1100;
const int M=100050;

struct node{
    int v,w,next;
};
node edge1[M];
int head[N];
node edge2[M];
int rhead[N];
int H[N];

struct PATH{
    int F,G,s;
    friend bool operator < (PATH a,PATH b){
        return a.F>b.F;
    }
};

void spfa(int s){
    queue<int>q;
    int vis[N]={0};
    q.push(s);vis[s]=1;H[s]=0;
    while(!q.empty()){
        s=q.front();
        q.pop();
        vis[s]=0;
        for(int i=rhead[s];~i;i=edge2[i].next){
            int j=edge2[i].v;
            if(H[j]>edge2[i].w+H[s]){
                H[j]=edge2[i].w+H[s];
                if(!vis[j]){
                    vis[j]=1,q.push(j);
                }
            }
        }
    }
}

int Astar(int st,int en,int K){
    spfa(en);
    if(H[st]==inf){
        return -1;
    }
    priority_queue<PATH> q;
    PATH p,tp;
    int k[N]={0};
    p.s=st;p.G=0;p.F=H[st];
    q.push(p);
    while(!q.empty()){
        p=q.top();
        q.pop();
        k[p.s]++;
        if(k[p.s]>K) continue;
        if(p.s==en&&k[p.s]==K) return p.F;
        for(int i=head[p.s];~i;i=edge1[i].next){
            int j=edge1[i].v;
            if(H[j]!=inf){
                tp.G=p.G+edge1[i].w;
                tp.F=H[j]+tp.G;
                tp.s=j;
                q.push(tp);
            }
        }
    }
    return -1;
}

int main(){
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        head[i]=-1;
        rhead[i]=-1;
        H[i]=inf;
    }
    int a,b,t,cnt=0;
    while(m--){
        scanf("%d%d%d",&a,&b,&t);
        edge1[cnt].v=b;
        edge1[cnt].w=t;
        edge1[cnt].next=head[a];
        head[a]=cnt;
        edge2[cnt].v=a;
        edge2[cnt].w=t;
        edge2[cnt].next=rhead[b];
        rhead[b]=cnt;
        cnt++;
    }
    int S,T,K;
    scanf("%d%d%d",&S,&T,&K);
    if(S==T){
       K++;
    }
    printf("%d\n",Astar(S,T,K));
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值