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
  • 相关阅读:
    poj 2584 T-Shirt Gumbo (二分匹配)
    hdu 1757 A Simple Math Problem (乘法矩阵)
    矩阵之矩阵乘法(转载)
    poj 2239 Selecting Courses (二分匹配)
    hdu 3661 Assignments (贪心)
    hdu 1348 Wall (凸包)
    poj 2060 Taxi Cab Scheme (二分匹配)
    hdu 2202 最大三角形 (凸包)
    hdu 1577 WisKey的眼神 (数学几何)
    poj 1719 Shooting Contest (二分匹配)
  • 原文地址:https://www.cnblogs.com/Cw-trip/p/4768150.html
Copyright © 2011-2022 走看看