POJ2449-Remmarguts' Date(K短路)

来源:互联网 发布:淘宝王子团队怎么联系 编辑:程序博客网 时间:2024/05/22 02:30

题目链接

http://poj.org/problem?id=2449

题意

求一个有向图的给定起点和终点的K短路

思路

A* + SPFA
A*算法的核心是估价函数f(n) = g(n) + h(n)的设计。
对于该题,设g(n)为当前点到起点的最近距离,h(n)为当前点到终点的最近距离,f(n) = h(n) + g(n)的第k大即为起点到终点的第K短路。
该题为有向图,于是先将所有边反向,从终点做一次单源最短路径,求出h(n)。在从起点单源最短路径,原来的d[]数组实际上就是估价函数f()。当终点第K次从优先队列中出来的时候得到的就是第K短路

细节

  1. 该图为有向图,因此求每个点到终点的最短路时,从终点做单源最短路径时应将所有边反向
  2. 起点和终点相同的时候,因为该题默认必须要经过边,所以要K++

证明

在图上,只要h(n)满足一致性,那么A*算法得到的一定是最优解
定义:
f(n):从初始状态到目标状态的估计代价
g(n):从初始状态到目前状态的实际代价
h(n):从目前状态到目标状态的估计代价
h(n)的一致性:设v为u的后继节点,则h(u) ≤ h(v) + w(u, v) (w(u, v)为u到v的代价)
该题的证明
首先证明该题中h(n)满足一致性:
在该题中,h(n)定义为当前节点u到目标节点t的最短路径,v为u的后继结点,那么只需要证明:h(u) ≤ h(v) + w(u, v)
反证法,假设h(u) > h(v) + w(u, v)。那么求t到u的最短路径时,h(u)可以直接更新为h(v) + w(u, v),即h(u)不是t到u的最短路径,矛盾。因此h(n)满足一致性定理
其次再证明在图搜索上,只要h(n)满足一致性,A*算法产生的即为最优解
I.证明沿着路径上扩展的f(n)一定是非递减的:
设v为u的后继结点,则f(v) = g(v) + h(v) = g(u) + w(u, v) + h(v) ≥ g(u) + h(u) = f(n)
II.证明第一次选择扩展目标节点的时候得到的是s到t的最优解
反证法, 假设存在另一个结点t’,并且t’更优,那么选择扩展的时候,一定先扩展t’而不是t,因此第一次扩展目标节点t的时候得到的是t的最优值
那么我们就得到了第一次扩展t的时候得到的是s到t的最短路,那么同理,第k次扩展到目标节点的时候得到的是第k短路,得证


代码

#include<iostream>#include<cstring>#include<stack>#include<vector>#include<set>#include<map>#include<algorithm>#include<cmath>#include<queue>#include<sstream>#include<iomanip>#include<fstream>#include<cstdio>#include<cstdlib>#include<climits>#include<deque>using namespace std;#define INF 10000000#define PI acos(-1.0)#define LL long long#define PII pair<int, int>#define PLL pair<LL, LL>#define mp make_pair#define IN freopen("in.txt", "r", stdin)#define OUT freopen("out.txt", "wb", stdout)#define scan(x) scanf("%d", &x)#define scan2(x, y) scanf("%d%d", &x, &y)#define sqr(x) (x) * (x)const int maxn = 1000 + 5;int N, M;struct Edge {    int from, to, dist;    Edge(int u, int v, int w) : from(u), to(v), dist(w) {    }};vector<Edge> edges;vector<Edge> redges;vector<int> G[maxn];vector<int> RG[maxn];void addedge(int u, int v, int w) {    edges.push_back(Edge(u, v, w));    int s = edges.size() - 1;    G[u].push_back(s);    redges.push_back(Edge(v, u, w));    s = redges.size() - 1;    RG[v].push_back(s);}int h[maxn];void spfa(int s) {    int inq[maxn];    memset(inq, 0, sizeof(inq));    queue<int> q;    for (int i = 1; i <= N; i++) h[i] = INF;    h[s] = 0;    inq[s] = 1;    q.push(s);    while (!q.empty()) {        int u = q.front();        q.pop();        inq[u] = 0;        int s = RG[u].size();        for (int i = 0; i < s; i++) {            Edge &e = redges[RG[u][i]];            if (h[u] < INF && h[e.to] > h[u] + e.dist) {                h[e.to] = h[u] + e.dist;                if (!inq[e.to]) {                    inq[e.to] = 1;                    q.push(e.to);                }            }        }    }}struct node {    int _f, _g, _v;    node (int x, int y, int z) : _f(x), _g(y), _v(z) {    }};struct cmp {    bool operator() (node x, node y) {        return x._f > y._f;    }};int Astar(int S, int T, int K) {    if (h[T] == INF) return -1;    if (S == T) K++;    int cnt[maxn], shortest;    memset(cnt, 0, sizeof(cnt));    priority_queue<node, vector<node>, cmp> q;    q.push(node(h[S] , 0, S));    while (!q.empty()) {        node t = q.top();        q.pop();        int u = t._v;        cnt[u]++;        if (u == T && cnt[T] == K) return t._f;        int s = G[u].size();        for (int i = 0; i < s; i++) {            Edge &e = edges[G[u][i]];            int g = t._g + e.dist;            int f = h[e.to] + g;            q.push(node(f, g, e.to));        }    }    return -1;}int main() {    scan2(N, M);    for (int i = 0; i < M; i++) {        int x, y, z;        scanf("%d%d%d", &x, &y, &z);        addedge(x, y, z);    }    int S, T, K;    scanf("%d%d%d", &S, &T, &K);    spfa(T);    printf("%d\n", Astar(S, T, K));    return 0;}
0 0
原创粉丝点击