poj 2449 (A* + Dijsktra 求K短路)

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

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

    2. 实现A*,f (x) = g(x) + h (x);定义估价函数。我们定义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, gv, d[v])-->(u, gu + cost[v][u], d[u])。

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

/***********************************************
 * Author: fisty
 * Created Time: 2015/2/1 20:14:57
 * File Name   : poj2449.cpp
 *********************************************** */
#include <iostream>
#include <cstring>
#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <algorithm>
using namespace std;
#define Debug(x) cout << #x << " " << x <<endl
#define MAX_N 1100
const int INF = 0x3f3f3f3f;
typedef long long LL;
typedef pair<int, int> P;
int n, m;
int start, end, K;
//最短路
struct edge{
    int to;
    int cost;
    edge(int _to, int _cost):to(_to), cost(_cost){}
};
vector<edge> _G[MAX_N];
int dist[MAX_N];                     //终点到各点的最短路

void dijsktra(int t){
    //t -> i
    priority_queue <P, vector<P>, greater<P> > que;
    memset(dist, 0x3f, sizeof(dist));
    dist[t] = 0;
    que.push(P(dist[t], t));
    while(que.size()){
        P q = que.top(); que.pop();
        int v = q.second;
        if(dist[v] < q.first) continue;
        for(int i = 0;i < _G[v].size(); i++){
            edge e = _G[v][i];
            if(dist[e.to] > dist[v] + e.cost){
                dist[e.to] = dist[v] + e.cost;
                que.push(P(dist[e.to], e.to));
            }
        }
    }
}

//Astar 
struct node{
    //定义了优先队列的结点
    //f = g + h, f小的优先出队
    int v;
    int g;               //g为节点start到i的实际值
    int h;               //h为节点i到end的最少估价值
    node(int _v,int _g, int _h):v(_v), g(_g), h(_h){}
    bool operator < (node a) const{
        return h + g > a.h + a.g;
    }
};
int cnt[MAX_N];                 //节点的计数,若大于K则剪枝。因为是第K短,1个顶点不会超过K次
vector<edge> G[MAX_N];
int A_star(){
    priority_queue <node> que;    
    memset(cnt, 0, sizeof(cnt));                
    que.push(node(start, 0, dist[start]));          //入队的信息为 起点,起点的启发值, h值
    while(que.size()){
        node e = que.top(); que.pop();
        int v = e.v, g = e.g, h = e.h;
        cnt[v]++;
        if(cnt[v] == K && v == end) return g ;
        if(cnt[v] > K) continue;
        for(int i = 0;i < G[v].size(); i++){
            edge e = G[v][i];
            que.push(node(e.to, e.cost + g, dist[e.to]));
        }
    }
    return -1;
}
int main(){
    //freopen("in.txt", "r", stdin);
    cin.tie(0);
    ios::sync_with_stdio(false);
    cin >> n >> m;
    for(int i = 0;i < m; i++){
        int u, v, cost;
        cin >> u >> v >> cost;
        G[u].push_back(edge(v, cost));
        _G[v].push_back(edge(u, cost));
   }
    cin >> start >> end >> K;
    if(start == end){  //起点终点相同,最短路为0
        ++K;   
    }
    dijsktra(end);
    int ans = A_star();
    if(ans == -1)
        cout << -1 << endl;
    else
        cout << ans << endl;
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值