poj 2449( k 短路 spfa+A*来求解)

看到了一个讲解k短路的感觉不错。。。。。

对于A* ,估价函数 = 当前值+当前位置到终点的距离,即 F(p)=g(p)+h(p),每次扩展估价函数值中最小的一个。对于k短路来说,g(p)为当前从s到p所走的长度,h(p)为从p到 t 的最短路的长度,则F(p)的意义就是从s按照当前路径走到 p 后要走到终点 t 一共至少要走多远。也就是说我们每次的扩展都是有方向的扩展,这样就可以提高求解速度和降低扩展的状态数目。为了加速计算,h(p)需要从A*搜索之前进行预处理,只要将原图的所有边反向,再从终点 t 做一次单源最短路径就可以得到每个点的h(p)了。

还有就是这个题意说是t到s的k短路。。但样例给的是s到t的所以就在写程序的时候求s到t的就可以了。。囧。。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
#define inf 1<<30
#define cc(m,v) memset(m,v,sizeof(m))
#define M 100005

struct node {
    int v, g, f, next; // f=g+h
    bool operator<(const node & t) const {
        if (t.f == f) return t.g < g;
        return t.f<f;
    }
} edge[M], edge1[M];
int head[1005], p, head1[1005], n, dis[1005];

void spfa(int s) {
    int u, v, i, j, cot[1005];
    queue<int> q;
    bool vis[1005];
    for (i = 0; i <= n; i++) dis[i] = inf, cot[i]=0, vis[i]=0;
    vis[s] = 1, dis[s] = 0, q.push(s);
    while (!q.empty()) {
        u = q.front(),q.pop(), vis[u] = 0, cot[u]++;
        if(cot[u]>=n) return ;
        for (j = head1[u]; j != -1; j = edge1[j].next)
            if (dis[v=edge1[j].v] > dis[u] + edge1[j].g) {
                dis[v]=dis[u]+edge1[j].g;
                if(!vis[v])
                    vis[v] = 1, q.push(v);
            }
    }
}

int a_star(int s, int t, int k) {
    int cnt = 0, i;
    struct node e, ne;
    priority_queue<node> que;
    if (s == t) k++;
    if (dis[s] == inf) return -1;
    e.v = s, e.g = 0, e.f = e.g + dis[e.v];
    que.push(e);
    while (!que.empty()) {
        e = que.top(), que.pop();
        if (e.v == t) {
            cnt++;
            if (cnt == k) return e.g;
        }
        for (i = head[e.v]; i != -1; i = edge[i].next) {
            ne.v = edge[i].v, ne.g = e.g + edge[i].g;
            ne.f = ne.g + dis[ne.v], que.push(ne);
        }
    }
    return -1;
}

void ainit() {
    p = 0, cc(head, -1), cc(head1, -1);
}

void addedge(int u, int v, int w) {
    edge[p].v = v, edge[p].g = w, edge[p].next = head[u], head[u] = p;
    edge1[p].v = u, edge1[p].g = w, edge1[p].next = head1[v], head1[v] = p++;
}

int main() {
    int s, m, t, u, v, w, i, k;
    while (scanf("%d%d", &n, &m) != -1) {
        ainit();
        for (i = 1; i <= m; i++) {
            scanf("%d%d%d", &u, &v, &w);
            addedge(u, v, w);
        }
        scanf("%d%d%d", &s, &t, &k);
        spfa(t);
        printf("%d\n", a_star(s, t, k));
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值