k短路 SPFA+A*算法 poj 2449

Remmarguts’ Date
Time Limit: 4000MS
Memory Limit: 65536K
Total Submissions: 26115
Accepted: 7097

Description
“Good man never makes girls wait or breaks an appointment!” said the mandarin duck father. Softly touching his little ducks’ head, he told them a story.

“Prince Remmarguts lives in his kingdom UDF – United Delta of Freedom. One day their neighboring country sent them Princess Uyuw on a diplomatic mission.”

“Erenow, the princess sent Remmarguts a letter, informing him that she would come to the hall and hold commercial talks with UDF if and only if the prince go and meet her via the K-th shortest path. (in fact, Uyuw does not want to come at all)”

Being interested in the trade development and such a lovely girl, Prince Remmarguts really became enamored. He needs you - the prime minister’s help!

DETAILS: UDF’s capital consists of N stations. The hall is numbered S, while the station numbered T denotes prince’ current place. M muddy directed sideways connect some of the stations. Remmarguts’ path to welcome the princess might include the same station twice or more than twice, even it is the station with number S or T. Different paths with same length will be considered disparate.

Input
The first line contains two integer numbers N and M (1 <= N <= 1000, 0 <= M <= 100000). Stations are numbered from 1 to N. Each of the following M lines contains three integer numbers A, B and T (1 <= A, B <= N, 1 <= T <= 100). It shows that there is a directed sideway from A-th station to B-th station with time T.

The last line consists of three integer numbers S, T and K (1 <= S, T <= N, 1 <= K <= 1000).

Output
A single line consisting of a single integer number: the length (time required) to welcome Princess Uyuw using the K-th shortest path. If K-th shortest path does not exist, you should output “-1” (without quotes) instead.

Sample Input

2 2
1 2 5
2 1 4
1 2 2

Sample Output

14

基本算法:


对于k短路,可以想到的一个比较朴素的算法就是宽度优先搜索,使用优先队列从源点s进行宽度优先遍历的时候,当第k次遍历到终点t的时候,所得的长度就是所求,但是这种方法在运行过程中会产生特别多的状态,当图比较简单,k比较小的时候可以一试,但是当k比较大或图比较复杂的时候就会爆栈。目前使用比较多的算法是单元最短路径配合A ,A是搜索中比较高级的方式,它结合了启发式(这种方法通过充分利用图给出的信息来动态地作出决定而使搜索次数大大降低)和形式化(这种方法不利用图给出的信息,而仅通过数学分析,如dijkstra算法)。它通过一个估价函数来估计图中当前节点p到终点的距离,并由此决定它的搜索方向,当这条路径失败时,他会尝试其他路径。对于A , 估价函数 = 当前值+当前位置到终点的距离,即f(p)=g(p)+h(p),每次扩展估价函数最小的一个。对于k短路算法来说,g(p)为当前从s到p所走的路径长度,h(p)为从p到t的最短路的长度,则f(p)的意义就是s到p所走的p后再走到t一共至少要走多远。也就是每次的扩展都是有方向的,这样无论对提高出解的速度还是降低扩展的状态数目都有好处。为了加速计算,h(p)需要在A <script id="MathJax-Element-1641" type="math/tex">*</script>s搜索之前进行预处理,只要将原图的所有边反向,再从终点t做一次最短路径就能够得到每个点的h(p)了。


代码:


#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include <stack>
#include <string>
#include <set>
#include <map>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#define maxn 100000+10
const int INF = 0x3f3f3f3f;
const int MAXX = 1000+10;
int n, m;
int head[maxn], head1[maxn];
bool vis[MAXX];
struct Edge
{
    int to, w, next;
}edge[maxn], edge1[maxn];

struct node
{
    int to;
    int f, g;
    bool operator < (const node &a)const
    {
        if (a.f == f)
            return g>a.g;
        return f>a.f;
    }
};
using namespace std;
int cnt;
int c;
int dis[MAXX];
int outq[MAXX];
void addedge(int u, int v, int c)
{
    edge[cnt].to = v;
    edge[cnt].w = c;
    edge[cnt].next = head[u];
    head[u] = cnt;
    cnt++;
}


void add(int u, int v, int cc)
{
    edge1[c].to = v;
    edge1[c].w = cc;
    edge1[c].next = head1[u];
    head1[u] = c;
    c++;
}

bool SPFA(int t)
{
    memset(dis, INF, sizeof(dis));
    memset(outq, 0, sizeof(outq));

    queue<int>q;
    memset(vis, false, sizeof(vis));
    q.push(t);
    vis[t] = true;
    dis[t] = 0;
    int u, v;
    while (!q.empty())
    {
        u = q.front();
        q.pop();
        outq[u]++;
        vis[u] = false;
        if (outq[u] > n)
            return false;
        for (int i=head1[u]; i!=-1; i=edge1[i].next)
        {
            v = edge1[i].to;
            if (dis[v] > dis[u]+edge1[i].w)
            {
                dis[v] = dis[u]+edge1[i].w;
                if (!vis[v])
                {
                    q.push(v);
                    vis[v] = true;
                }
            }
        }
    }
    return true;
}


int a_star(int s, int t, int k, int head[MAXX], Edge edge[MAXX])
{
    node e, ne;
    int tt=0;
    priority_queue<node>q;
    if (s == t)
        k++;
    if (dis[s] == INF)
        return -1;
    e.to = s;
    e.g = 0;
    e.f = e.g+dis[e.to];
    q.push(e);
    while (!q.empty())
    {
        e = q.top();
        q.pop();
        if (e.to == t)
            tt++;
        if (tt == k)
            return e.g;
        for (int i=head[e.to]; i!=-1; i=edge[i].next)
        {
            ne.to = edge[i].to;
            ne.g = e.g+edge[i].w;
            ne.f = ne.g+dis[ne.to];
            q.push(ne);
        }
    }
    return -1;
}

int main()
{
    while (scanf("%d%d", &n, &m)!=EOF)
    {
        c = cnt = 0;
        memset(head, -1,  sizeof(head));
        memset(head1, -1,  sizeof(head1));
        for (int i=0; i<m; i++)
        {
            int u, v, c;
            scanf("%d%d%d", &u, &v, &c);
            addedge(u, v, c);
            add(v, u, c);
        }
        int s, t, k;
        scanf("%d%d%d", &s, &t, &k);
        SPFA(t);
        int kthlength = a_star(s, t, k, head, edge);
        printf("%d\n", kthlength);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值