• 《算法竞赛进阶指南》0x27 A*算法求解第K短路 POJ2449


    题目链接:http://poj.org/problem?id=2449

    dijkstra算法中,一个点第一次从堆中出来的时候一定是最短路,第K次出来的时候一定是第k短路。

    求解中可以使用A*设计估价函数使得结果朝着目标更快的收敛,本题设计的估计函数是该点到终点的最短路,因为这个最短路一定是小于目标函数的结果的,可以证明估计函数在这样的取值下一定能够收敛。

    每次从堆中取出最优的点进行扩展,不断更新估计距离以及实际距离,最终一定能够快速收敛到答案。

    注意求估价函数的过程是反图求最短路,多源而只有一个终点,可以直接对反图进行操作。另一个注意点就是,当终点和起点一致的时候就需要忽略长度为0的最短路,也就是选择k+1短路,

    要使k++。

    代码:

    #include<iostream>
    #include<queue>
    #include<cstring>
    using namespace std;
    #define maxn 1005
    #define maxm 100010
    #define P pair<int,int>
    #define PIII pair<int,pair<int,int>>
    int head[maxn],nxt[maxm*2],rhead[maxn] ,len[maxm*2],ver[maxm*2];
    int tot=0;
    bool vis[maxn];
    int d[maxn],cnt[maxn];
    int st,ed,k,n,m;
    void addedge(int* head,int u,int v,int w){
        ver[++tot]=v;
        len[tot]=w;
        nxt[tot]=head[u];
        head[u]=tot;
    }
    void dijkstra(int s){
        memset(vis,false,sizeof(vis));
        memset(d,0x3f,sizeof(d));
        d[s]=0;
        priority_queue<P,vector<P>,greater<P> > q;
        q.push(make_pair(0,s));
        while(!q.empty()){
            pair<int,int> cur=q.top();
            q.pop();
            int x=cur.second;
            if(vis[x])continue;
            vis[x]=1;
            for(int i=rhead[x];i;i=nxt[i]){
                int y=ver[i];
                int length=len[i];
                if(d[y]>d[x]+length)
                {
                    d[y]=d[x]+length;
                    q.push(make_pair(d[y],y));
                }
            }
        }
    }
    int A_star(){
        if(st==ed)++k;
        memset(cnt,0,sizeof(cnt));
        priority_queue<PIII,vector<PIII>,greater<PIII> > heap;
        heap.push(make_pair(d[st],make_pair(0,st)));//三元组,分别是估计值,真实距离和编号
        
        while(heap.size()){
            PIII now=heap.top();
            heap.pop();
            int x=now.second.second;
            int distance=now.second.first;//顶点和实际距离 
            if(cnt[x]==k)continue;
            cnt[x]++;
            if(x==ed && cnt[x]==k)return distance;
            for(int i=head[x];i;i=nxt[i]){
                int y=ver[i],length=len[i];
                if(cnt[y]<k){
                    heap.push(make_pair(distance+length+d[y],make_pair(distance+length,y)));
                }
            }
        }
        return -1;
    }
    int main(){
        cin>>n>>m;
        int u,v,w;
        for(int i=1;i<=m;i++){
            scanf("%d%d%d",&u,&v,&w);
            //保存原图以及反图 
            addedge(head,u,v,w);
            addedge(rhead,v,u,w);
        }
        
        cin>>st>>ed>>k;
        dijkstra(ed);
        cout<<A_star()<<endl;
    }
  • 相关阅读:
    使用apt-mirror建立本地debian仓库源
    在MacOS上利用docker构建buildroot
    mac开发错误:errSecInternalComponent
    NFS作为根文件系统,挂载超时
    关于物体 '固有类别' 与 '实际使用类别' 分离的情况,结构体定义方法
    Crontab could not create directory .ssh
    mac bash_profile
    Mac bash rc
    watchtower无法自动更新镜像的解决方法
    spring security oAuth2.0 数据库说明
  • 原文地址:https://www.cnblogs.com/randy-lo/p/13171849.html
Copyright © 2020-2023  润新知