• POJ 2449 Remmarguts' Date (SPFA + A星算法)


            题目大意:给你一个有向图,并给你三个数s、t 和 k ,让你求从点 s 到 点 t 的第 k 短的路径。如果第 k 短路不存在,则输出“-1” ,否则,输出第 k 短路的长度。

            解题思路:这道题是一道简单的启发式搜索题目。而启发式搜索中A星算法是比较好理解的。A星算法中需要用到一个估价函数:f(n) = g(n)+ h(n)。其中,g(n)是当前量,h(n)是估计量,两者之和 f(n) 是估计值 。在这道题中,g(n)是从起点 s 到 点n 的已走距离,h(n)是从点n 到终点 t 的最短距离(dis[ n ]) 。每当我们走到一个点 tn 时 ,就计算出此时 tn 的g(tn) 、 h(tn)和 f(tn),把 tn 的这些信息压入一个队列,然后下一步选取队列中 f 值最小的节点作为下一步搜索的起点,如此反复,当我们第k次搜索到终点 t 时 ,这时g(t)的值就是我们要求的值。

            Ps:这里我们需要用到优先队列,并且要注意:因为必须离开 s 点再返回,所以,当 s == t 时 ,k ++ 。

    请看代码:

    #include<iostream>
    #include<cstring>
    #include<algorithm>
    #include<string>
    #include<cmath>
    #include<vector>
    #include<cstdio>
    #include<queue>
    #define mem(a , b) memset(a , b , sizeof(a))
    using namespace std ;
    inline void RD(int &a)
    {
        a = 0 ;
        char t ;
        do
        {
            t = getchar() ;
        }
        while (t < '0' || t > '9') ;
        a = t - '0' ;
        while ((t = getchar()) >= '0' && t <= '9')
        {
            a = a * 10 + t - '0' ;
        }
    }
    inline void OT(int a)
    {
        if(a >= 10)
        {
            OT(a / 10) ;
        }
        putchar(a % 10 + '0') ;
    }
    const int N = 1005 ;
    const int M = 1e5 + 5 ;
    const int INF = 0x7fffffff ;
    struct Edge
    {
        int adj ;
        int d ;
        int next ;
    } E[M * 3] ;
    int head[N] ;
    int headN[N] ; // 反向图
    int dis[N] ;
    bool inq[N] ;
    int s , t , k ;
    int n , m ;
    int ce ;
    void chu()
    {
        mem(head , - 1) ;
        mem(headN , -1) ;
        mem(inq , 0) ;
        ce = 0 ;
    }
    void init()
    {
        chu() ;
        int i ;
        for(i = 0 ; i < m ; i ++)
        {
            int a , b , c ;
            scanf("%d%d%d" , &a , &b , &c) ;
            ce ++ ;
            E[ce].adj = b ;
            E[ce].d = c ;
            E[ce].next = head[a] ;
            head[a] = ce ;
    
            ce ++ ;
            E[ce].adj = a ;
            E[ce].d = c ;
            E[ce].next = headN[b] ;
            headN[b] = ce ;
        }
        scanf("%d%d%d" , &s , &t , &k) ;
    }
    queue<int> q ;
    void spfa()  // 计算 dis
    {
        while (!q.empty()) q.pop() ;
        q.push(t) ;
        inq[t] = true ;
        int v ;
        while (!q.empty())
        {
            v = q.front() ;
            q.pop() ;
            inq[v] = false ;
            int i ;
            for(i = headN[v] ; i != -1 ; i = E[i].next)
            {
                int tv = E[i].adj ;
                int td = E[i].d ;
                if(dis[v] + td < dis[tv])
                {
                    dis[tv] = dis[v] + td ;
                    if(!inq[tv])
                    {
                        q.push(tv) ;
                        inq[tv] = true ;
                    }
                }
            }
        }
    }
    struct F
    {
        int Node ;
        int f ;
        int g ;
        int h ;
    };
    struct cmp
    {
        bool operator () (F a , F b)
        {
            if(a.f == b.f)
            {
                return a.g > b.g ;
            }
            return a.f > b.f ;
        }
    } ;
    priority_queue<F, vector<F> , cmp> mq ;
    int SP()  // A星 算法
    {
        if(s == t) k ++ ;
        while (!mq.empty()) mq.pop() ; // 注意队列要清空
        int cnt = 0 ;
        F u ;
        u.Node = s ;
        u.g = 0 ;
        u.h = dis[s] ;
        u.f = u.g + u.h ;
        mq.push(u) ;
        while (!mq.empty())
        {
            F v = mq.top() ;
            if(v.Node == t)
            {
                cnt ++ ;
                if(cnt == k)
                {
                    return v.g ;
                }
            }
            mq.pop() ;
            int i ;
            for(i = head[v.Node] ; i != -1 ; i = E[i].next)
            {
                int tv = E[i].adj ;
                int td = E[i].d ;
                F tmp ;
                tmp.Node = tv ;
                tmp.g = v.g + td ;
                tmp.h = dis[tv] ;
                tmp.f = tmp.g + tmp.h ;
                mq.push(tmp) ;
            }
        }
        return -1 ; // 注意:因为此图是有向图,所以K短路可能不存在!!!
    }
    void solve()
    {
        int i ;
        for(i = 1 ; i <= n ; i ++)
        {
            dis[i] = INF ;
        }
        dis[t] = 0 ;
        spfa() ;
        if(dis[s] == INF)
        {
            puts("-1") ;
            return ;
        }
        else
        {
            printf("%d
    " , SP()) ;
        }
    }
    int main()
    {
        while (scanf("%d%d" , &n , &m) != EOF)
        {
            init() ;
            solve() ;
        }
        return 0 ;
    }
    



  • 相关阅读:
    路径规划 Adjacency matrix 传球问题
    Graph
    n的阶乘的n次方根的倒数的序列为无穷小序列
    原文来自 url get
    对称加密 非对称加密 生活模型
    签名 sign key 纸质邮件 历史 RSA诞生历史
    离散数学图论
    内联函数
    由适当地放宽不等式 概括出 一个引理
    序列 有界 无界的证明
  • 原文地址:https://www.cnblogs.com/pangblog/p/3347894.html
Copyright © 2020-2023  润新知