poj 2449 A* +Dijkstra求第K短路(模板题)

来源:互联网 发布:原材料明细账软件 编辑:程序博客网 时间:2024/06/05 07:09

    所谓K短路,就是从s到t的第K短的路,第1短就是最短路。

    如何求第K短呢?有一种简单的方法是广度优先搜索,记录t出队列的次数,当t第k次出队列时,就是第k短路了。但点数过大时,入队列的节点过多,时间和空间复杂度都较高。

    A*是在搜索中常用的优化,一种启发式搜索。简单的说,它可以用公式表示为f(n) = g(n) + f(n),其中,f(n)是从s经由节点n到t的估价函数,g(n)是在状态空间中从s到n的实际代价,h(n)是从n到t的最佳路径估计代价。在设计中,要保证h(n)<= n到t的实际代价,这一点很重要,h(n)越接近真实值,速度越快。

    由于启发函数的作用,使得计算机在进行状态转移时尽量避开不可能产生最优解的分支,而选择相对较接近最优解的路径进行搜索,降低了时间和空间复杂度。

    算法过程:

    1. 将图反向,用dijstra+heap求出t到所有点的最短距离,目的是求所有点到点t的最短路,用dis[i]表示i到t的最短路,其实这就是A*的启发函数,显然:h(n)<= n到t的实际代价。

    2. 定义估价函数。我们定义g(n)为从s到n所花费的代价,h(n)为dis[n],显然这符合A*算法的要求。

    3. 初始化状态。状态中存放当前到达的点i,fi,gi。显然,fi=gi+dis[i]。初始状态为(S,dis[S],0),存入优先级队列中。

    4. 状态转移。假设当前状态所在的点v相邻的点u,我们可以得到转换:(V,fv,gv)-->(U,fu+w[v][u],gv+w[v][u])。

    5. 终止条件。每个节点最多入队列K次,当t出队列K次时,即找到解。


#include <cstdio>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;


#define mpair make_pair
#define pii pair<int,int>
#define MM(a,b) memset(a,b,sizeof(a));
typedef long long lld;
typedef unsigned long long u64;
template<class T> bool up_max(T& a,const T& b){return b>a? a=b,1 : 0;}
template<class T> bool up_min(T& a,const T& b){return b<a? a=b,1 : 0;}
#define maxn 1005
const int inf= 2100000000;


int n,m;
vector< pii > e[maxn], e2[maxn];


int dis[maxn];
bool vis[maxn];
void Dijkstra(int st)
{
    for(int i=1;i<=n;++i) dis[i]= inf, vis[i]= 0;
    dis[st]= 0,  vis[st]= 1;
    for(int i=0;i<e2[st].size();++i)
        up_min( dis[ e2[st][i].first ], e2[st][i].second );


    while(1){
        int mdis= inf, idx= -1;
        for(int i=1;i<=n;++i){
            if( !vis[i] && up_min( mdis, dis[i] ) )
                idx= i;
        }
        if( -1 == idx ) break;
        vis[idx]= 1;
        for(int i=0;i<e2[idx].size();++i){
            int v= e2[idx][i].first, w= e2[idx][i].second;
            if( !vis[v] )
                up_min( dis[v], dis[idx] + w );
        }
    }
}


struct Node
{
    int u, h, g; /// h[u]+g[u];
    Node(int u_,int h_,int g_)
    {u=u_,h=h_,g=g_;}
    bool operator<(Node a)const
    {
        return h+g > a.h+a.g;
    }
};
priority_queue<Node>Q;


int cnt[maxn];
int Astar(int st, int ed, int k){ /// A*: return the k-th shortest path from st to ed;
    while( !Q.empty() ) Q.pop();
    fill( cnt, cnt+1+n, 0 );
    Q.push( Node( st, 0, dis[st] ) );


    while( !Q.empty() ){
        Node a= Q.top(); Q.pop();
        int u= a.u, h= a.h, g= a.g;
        ++cnt[u];
        if( cnt[u]==k && u==ed ) return h;
        if( cnt[u]>k ) continue;
        for(int i=0;i<e[u].size();++i){
            int v= e[u][i].first, w= e[u][i].second;
            Q.push( Node( v, h+w, dis[v] ) );
        }
    }
    return -1;
}


int main()
{
    while( cin>>n>>m )
    {
        for(int i=1;i<=n;++i)
        e[i].clear(), e2[i].clear();
        while(m--)
        {
            int u,v,w;
            scanf("%d%d%d", &u, &v, &w);
            e[u].push_back( pii( v, w ) );
            e2[v].push_back( pii( u, w ) );
        }


        int st, ed, k;
        cin>>st>>ed>>k;
        if( st==ed ) ++k;
        Dijkstra( ed ); /// ed;
        cout<< Astar( st, ed, k ) <<endl;
    }
}

原创粉丝点击