POJ 2449 K短路(A*)

POJ 2449
复杂度O(nk)
注意图不连通 起始点终点为同一点的情况
#include <cstdio>
#include<queue>
#include<cstring>
using namespace std;
typedef long long LL;
const LL maxn = 1000 + 100;
const LL maxm = 200000 + 100;
const LL inf = 0x3f3f3f3f3f3f3f3f;
LL he2[maxn],ne2[maxm],ver2[maxm],tot2,cost2[maxm];
LL dist[maxn],vis[maxn];
void add2( LL x,LL y,LL c ){
    ver2[++tot2] = y;
    ne2[tot2] = he2[x];
    he2[x] = tot2;
    cost2[tot2] = c;
}
priority_queue< pair<LL,LL>,vector< pair<LL,LL> >,greater< pair<LL,LL> > > que2;
void dijkstra( LL S,LL T ){
    while( que2.size() ) que2.pop();
    dist[S] = 0;
    que2.push( make_pair( 0,S ) );
    while( que2.size() ){
        LL x = que2.top().second;
        que2.pop();
        //if( x == T ) break;
        if( vis[x] ) continue;
        vis[x] = 1;
        for( LL cure = he2[x];cure;cure = ne2[cure] ){
            LL y = ver2[cure];
            if( vis[y] ) continue;
            if( dist[y] > dist[x] + cost2[cure] ){
                dist[y] = dist[x] + cost2[cure];
                que2.push( make_pair( dist[y],y ) );
            }
        }
    }
}
LL he[maxn],ne[maxm],ver[maxm],tot,cost[maxm];
void add( LL x,LL y,LL c ){
    ver[++tot] = y;
    ne[tot] = he[x];
    he[x] = tot;
    cost[tot] = c;
}
priority_queue< pair<LL, pair<LL,LL> > ,vector< pair< LL,pair<LL,LL> > >,greater< pair< LL,pair<LL,LL> > > > que;
LL solve( LL S,LL T,LL k ){
    while( que.size() ) que.pop();
    que.push( make_pair( dist[S], make_pair( 0 , S )  ) );
    LL ans = 0;
    while( que.size() ){
        LL d = que.top().second.first;
        LL x = que.top().second.second;
        if( x == T ){
            ans++;
            if( ans == k ) return que.top().first;
        }
        que.pop();
        for( LL cure = he[x];cure;cure = ne[cure] ){
            LL y = ver[cure];
            que.push( make_pair( d+ cost[cure] + dist[ y ],make_pair( d + cost[cure] ,y ) ) );
        }
    }
    return -1;
}
void init( LL n ){
    for( LL i = 1; i <= n;i++ ){
        he[i] = he2[i] = vis[i] = 0;
        dist[i] = inf;
    }
    tot = tot2 = 1;
}
int main()
{
    LL n,m,a,b,t,S,T,k;
    while( 2 == scanf("%lld%lld",&n,&m) ){
        init( n );
        for( LL i = 1;i <= m;i++ ){
            scanf("%lld%lld%lld",&a,&b,&t);
            add( a,b,t );
            add2( b,a,t );
        }
        scanf("%lld%lld%lld",&S,&T,&k);
        if( S == T ) k++;
        dijkstra( T,S );
        if( dist[S] == inf ){
            printf("-1\n");
            continue;
        }
        LL ans = solve( S,T,k );
        printf("%lld\n",ans);
    }
    return 0;
}

下面写一下对于A*算法的个人理解,大佬请移步

记 起始点 S,终点T。S走到当前节点 i 的实际代价 g( i ),S走到 i 最小代价 g*(i),i 走到 T 的最小代价h*( i )。i走到T的估价 h(i)

记c(i,j)为节点 i 到 j 的最短路径

1.保证第一次扩展 T 时即得到最短路得条件:h( n )  < h*( n )

证明:易知最短路径上的某一点一定会在优先队列中,设此节点为  i  且此节点的权值是 f( i ) = g( i ) + h( i ) ,又 i为最短路径中的点,则 g(i) = g*( i )。

下面用反证法

假设节点 i 在被取出前 T已经被取出,则 f( T )  <  f( i )  => g( T )  <  g( i ) + h( i )  => g( T )  <  g*( i ) + h( i ) => g( T ) < g*( T )

显然不成立。

2.保证第一次扩展任意一节点  k 时即得到 S到 k 的最短路径的条件  c(i , j)> h( j )  - h( i )

证明:可以将 h( j ) - h( i )  理解为 i 到 j 的估价函数。则证明同上

 

于是易知 A* k短路算法的正确性,T第k次出队列的 时即为 第k短路。

同时还可以得到一个小结论:

dijsktra 可理解为估价值为0的A* 则其同时满则条件1和条件2,于是每个节点第一次扩展时即可得到到该点的最短路。

第k次扩展时便可得到起点到该点的第k短路。同样的结论应用于该题的A*算法中时只对于 终点 T成立,原因请读者自行思考。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值