zoukankan      html  css  js  c++  java
  • POJ 2449(求k短路,A*)

    题目:求s到t的第k短路。

    思路:网上是清一色的A*算法,所以学习了一下。所谓Astar算法其实就是启发式的bfs。这里设置了一个估价函数h,结合当前位置的最短路和到终点的估计最短路长度来选择下一个要扩展的节点(dijkstra算法对于所有的点的h值可以视为是一样的,所以下一个扩展的节点只与当前的最短路g有关)。这个h的值越接近手记最短路越好,但是不能少于实际最短路(否则会错误),假设h值就是实际最短路的值,那么这个Astar算法可以一次找到最短路,相对的,如果h比实际值稍大,那么仍然可以去掉很多无意义的搜索量。此题要求k短路,如果不用astar算法几乎没法搜。。。

    对于这个题,我们可以取h值等于实际值,这个可以通过把边反向跑一次最短路求得。然后依然从s开始搜,但是把优先队列的关键字改为f=g+h,优先对f小的点扩展。首先搜到的肯定是原最短路上的点,等到原来的最短路搜完了,队列中的f的最小值就会变大,此时再取出的点可能是之前扩展过的,但是搜到的是长度更长的另一条路。不论是第几长路,每次扩展肯定会把这个长度的路全部扩展完(到达t)才会搜索更长的路,所以肯定有cnt[t]==k的时候,此时扩展到t的路的长度就是k长路的长度。另外,如果s和t不连通而存在s可达的圈的话就要判断一下每个点的扩展次数超过k就跳出,否则会死循环。

    Ps:此题当s==t的时候k要加1,大概是因为必须得走路才行,因为这个wa了好久==

    /*
    * @author:  Cwind
    * http://www.cnblogs.com/Cw-trip/
    */
    #include <iostream>
    #include <map>
    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <vector>
    #include <queue>
    #include <stack>
    #include <functional>
    #include <set>
    #define pb push_back
    #define fs first
    #define se second
    #define bk back()
    using namespace std;
    typedef long long ll;
    typedef pair<ll,ll> P;
    
    const int maxn=1020;
    int n,m;
    int S,T,K;
    struct EDGE{
        int to,d;
        EDGE(int to,int d):to(to),d(d){}
    };
    vector<EDGE> G[maxn],rG[maxn];
    
    ll h[maxn];
    int cnt[maxn];
    void init(){
        memset(h,0x2f,sizeof h);
        h[T]=0;
        priority_queue<P,vector<P>,greater<P> > Q;
        Q.push(P(0,T));
        while(!Q.empty()){
            ll v=Q.top().se,d=Q.top().fs;
            Q.pop();
            if(h[v]<d) continue;
            for(int i=0;i<rG[v].size();i++){
                EDGE &e=rG[v][i];
                if(h[e.to]>h[v]+e.d){
                    h[e.to]=h[v]+e.d;
                    Q.push(P(h[e.to],e.to));
                }
            }
        }
    }
    struct A{
        ll f,g,p;
        A(ll f,ll g,ll p):f(f),g(g),p(p){}
        bool operator < (const A &C)const {
            return f>C.f;
        }
    };
    ll Astar(){
        priority_queue<A> Q;
        Q.push(A(h[S],0,S));
        while(!Q.empty()){
            A stg=Q.top();Q.pop();
            cnt[stg.p]++;
            if(stg.p==T&&cnt[T]==K){
                return stg.f;
            }
            if(cnt[stg.p]>K) continue;
            for(int i=0;i<G[stg.p].size();i++){
                EDGE &e=G[stg.p][i];
                Q.push(A(stg.g+e.d+h[e.to],stg.g+e.d,e.to));
            }
        }
        return -1;
    }
    int main(){
        freopen("/home/files/CppFiles/in","r",stdin);
        cin>>n>>m;
        for(int i=0;i<m;i++){
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            G[a].pb(EDGE(b,c));
            rG[b].pb(EDGE(a,c));
        }
        cin>>S>>T>>K;
        init();
        if(S==T) K++;
        ll ans=Astar();
        cout<<ans<<endl;
        return 0;
    }
    View Code
  • 相关阅读:
    弄懂Java为何只有值传递
    反转链表进阶
    剑指Offer-16:合并两个有序链表
    剑指Offer-15:反转链表
    剑指Offer-14:输入一个链表,输出该链表中倒数第k个结点。
    剑指Offer-13:调整数组位置使奇数位于偶数前面
    Java实现二分查找
    LDAP
    关于Prometheus运维实践项目
    LDAP-openldap服务部署和测试(YUM安装)
  • 原文地址:https://www.cnblogs.com/Cw-trip/p/4768150.html
Copyright © 2011-2022 走看看