A*+spfa
一张图,找K短路
转自:http://blog.csdn.net/mbxc816/article/details/7197228
“描述一下怎样用启发式搜索来解决K短路。
首先我们知道A*的基础公式:f(x)=g(x)+h(x);对h(x)进行设计,根据定义h(x)为当前的x点到目标点t所需要的实际距离。也就是说x->t距离,由于有很多的节点都是到t的距离,为了计算这个估计值,当然必须先算出x->t的最短路径长度。显然x的值很多而t的值只有一个,对每个x去求单源点最短路径当然不划算!于是反过来做,从t点出发到其他点的单源点最短路径,这样吧估价函数h(x)都求出来,注意这样求出来的h(x)=h*(x);
然后就可以对构造完的h(x)开始启发式搜索了。
首先的点当然就是定义头结点了,头结点的已消耗代价为0,估计代价为h[s],下一个点为v;进入队列,开始for循环。每次取出队头的f(x)最小的节点对其他节点进行拓展。对当前节点的拓展次数++,若当前节点的拓展次数超过K,显然不符合要求,则不进行拓展。若对t节点的拓展次数恰好为K,则找到了所需要的。对当前节点的拓展次数即为到当前节点的第几短路。找到需要节点的K短路后,返回g(t)即可,也就是通过K次拓展的实际消耗的长度。
在for循环中的入队情况:当前节点的可拓展所有边,的所有状态都入队,当前节点到拓展节点的实际代价为当前节点的实际代价+两节点之间的边长。下个节点就是拓展节点,估计函数的值则为拓展节点到目标节点的距离h(x);”
这个题目是单向边,所以有一点点麻烦,
f = g + h;
g 是从起点到当前点的距离
h 是从当前点到尾点的距离
首先我们就要把 h 求出来,就是最短路,从结尾点开始,跑spfa
求出到每个点的最短距离。这样 h 就出来了
因为是从结尾点开始搜,所以要倒着建边。
而顺着建边是为了搜 g,,
// Layout.cpp: 定义控制台应用程序的入口点。 // #include "stdafx.h" #include<cstdio> #include<queue> using namespace std; const int N = 1009; const int INF = 0x3f3f3f3f; struct node { int v, w,next; }; int sign,head[N],dis[N],st,en,k,rehead[N]; node p[200500],rep[200500]; void add(int x, int y, int z) { sign++; p[sign].next = head[x]; p[sign].v = y; p[sign].w = z; head[x] = sign; rep[sign].next = rehead[y]; rep[sign].v = x; rep[sign].w = z; rehead[y] = sign; return; } void spfa(int x,int *d) { int u, v; bool mark[N]; memset(mark, 0, sizeof(mark)); int l, r; queue<int>q; d[x] = 0; mark[x] = 1; q.push(x); while (!q.empty()) { u = q.front(); q.pop(); mark[u] = 0; for (int i = rehead[u]; i; i = rep[i].next) { v = rep[i].v; if (d[v] > d[u] + rep[i].w) { d[v] = d[u] + rep[i].w; if (!mark[v]) { mark[v] = 1; q.push(v); } } } } return; } struct edge { int pos; int h, g; bool operator < (const edge & a) const { return a.h + a.g < h + g; } }; int Astar() { int cnt = 0; if (st == en) k++; //要多加一次,首尾点一样。一开始就是尾点。 if (dis[st] == INF) return -1; priority_queue<edge>q; edge now, nxt; now.pos = st; now.g = 0; now.h = dis[st]; q.push(now); while (!q.empty()) { nxt = q.top(); q.pop(); if (nxt.pos == en) //因为一开始就是尾点,所以cnt加一,而cnt不该加一 { cnt++; if (cnt == k) return nxt.g; } for (int i = head[nxt.pos]; i; i = p[i].next) { now.pos = p[i].v; now.g = nxt.g + p[i].w; now.h = dis[p[i].v]; q.push(now); } } return -1; } int main() { int m, n, x, y, z; scanf("%d%d", &n, &m); for (int i = 1; i <= m; i++) { scanf("%d%d%d", &x, &y, &z); add(x, y, z); //add(y, x, z); } scanf("%d%d%d", &st, &en, &k); memset(dis, INF, sizeof(dis)); spfa(en, dis); printf("%d\n", Astar()); return 0; }