k短路问题(poj2449)(SPFA+A*)

k短路问题:A*就是给搜索算法一个大致的导向,尽量不往不必要的方向去搜索,也许也是因此叫做启发式搜索算法,就拿普通BFS比较吧,也就是一个退化了的A*,没有任何的导向,完全按照压入队列的时间顺序进行搜索,比如一个任意一点都可以站立的地图,人在中间,而目的地在右上角,显然BFS在到达目的地之前一定会对地图中大部分包括跟目的地相反方向的那些地方都搜索过,即越走越远,但是BFS不知道这些,只知道一层一层地扩展,即使走反了,如果有用标记或者染色,会发现地图上大部分无用、完全不必要的地区都被标记或染色过……因此BFS在数据范围较大的时候是比较慢的

而A*不一样,比BFS多了一个估价(启发)函数。

所谓A*就是启发式搜索..说白了就是给BFS搜索一个顺序使得搜索更加合理减少无谓的搜索..如何来确定搜索的顺序?..也就是用一个值来表示这个值为f[x]..每次搜索取f[x]最小的进行拓展...f[x]=h[x]+g[x]其中h[x]就是当前搜索时的实际代价...估价函数要小于是对当前点到目标的代价的估计..这个估计必须小于等于实际值~~否则会出错...A*的关键也就是构造g[x]..

在图的搜索里面构造g[x]用的比较多的是欧氏距离、曼哈顿距离、切比雪夫距离(这个比较高端感觉不太用的上……)

题目:传送门

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

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

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

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

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

两种解法:第一种使用vector存的邻接表,第二种使用链式前向星存的邻接表

第一种代码(vector):


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

using namespace std;

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

struct node{
    int v,w;
};
vector<node> map[N],tmap[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;
        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){
    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;
        int m=map[p.s].size();
        for(int i=0;i<m;i++){
            int j=map[p.s][i].v;
            if(H[j]!=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;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        map[i].clear();
        tmap[i].clear();
        H[i]=inf;
    }
    int a,b,t;
    node p;
    while(m--){
        scanf("%d%d%d",&a,&b,&t);
        p.w=t;
        p.v=b;map[a].push_back(p);
        p.v=a;tmap[b].push_back(p);
    }
    int S,T,K;
    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;
}

猜你喜欢

转载自blog.csdn.net/zhouzi2018/article/details/81567856