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

来源:互联网 发布:哈谢克 知乎 编辑:程序博客网 时间:2024/05/22 14:08

看到了一个讲解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 100005struct 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;}