Remmarguts' Date POJ - 2449 (A*搜索|k短路)

"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

题意:n个点,m条边的有向图,每个点可以多次抵达,给出s、t、k,求从s到t的第k短路思路:求最短路最常用的就是堆优化的dijkstra,那么很容易想到的一种写法:用dijkstra,当t第k次出现,那就是第k短路;但是如果有些状态当前值很小,但是未来值很大,优先队列就会先去扩展这个状态,这样的情况多了,就会导致搜索量增大。

优先队列是以当前所走过的路程最小的为优先的,它并不知道该状态后面的情况,所有排序并不是很完美,这时候我们就可以想到为其加入评估函数(估计该状态后面所需的路程),并且评估值<=实际值。这样我们使用优先队列是,将(该状态花费+评估值,节点)送入队列,取出时是总体评估最小,也就是不仅考虑了已走路程,顺便考虑了其后续可能路程,取出之后,花费-该点评估值==实际花费,然后扩展该状态,将(状态实际花费+下个点评估值+该路径长度)送入队列这样当t出项k次时出现的就是第k短路因为 评估值<=实际值,所以状态花费+评估值 <= 状态花费+实际值 == s(总花费),所以最优值肯定会在次优值之前出栈,(虽然之前的优先队列也这样)而且因为评估了后续所需,所以不会出现前小后大的非最优花费大量在队列前扩展,尽量让其直接将最优解排在队列前扩展,少扩展其他分支。

那么这个题的评估函数怎么求呢,因为我们是求到t的k短路,那么我们就把所有点到t的对短路当成评估函数,也就是以t为原点,求一遍最短路,刚好这个值可以反应未来变化的趋势和相对大小关系注:该题当s==t时,0并不是第一条路

#include<iostream>
#include<cstdio>
#include<queue>
#include<string.h>
using namespace std;

int n,m;
typedef pair<int,int>p;
struct E
{
    int x,y,val;
    int next;
    E(int x=0,int y=0,int val=0,int next=-1):x(x),y(y),val(val),next(next){}
}edge[100005];
int next[1005];
int cnt;
E t_edge[100005];
int t_next[1005];
int t_cnt;
int f[1005];
int ans[1005];
void add(int x,int y,int val)
{
    edge[++cnt] = E(x,y,val,next[x]);
    next[x] = cnt;
    t_edge[++t_cnt] = E(y,x,val,t_next[y]);
    t_next[y] = t_cnt;
}

void get_f(int t)
{
    memset(f,0x3f,sizeof(f));
    priority_queue<p,vector<p>,greater<p> >que;
    while(!que.empty())que.pop();
    que.push(p(0,t));
    while(!que.empty())
    {
        p tmp = que.top();
        que.pop();
        int now = tmp.second;
        int cost = tmp.first;
        if(f[now] != 0x3f3f3f3f)continue;
        f[now] = cost;
        for(int i=t_next[now];i!=-1;i=t_edge[i].next)
        {
            if(f[now] + t_edge[i].val < f[t_edge[i].y])
            {

                que.push(p(f[now] + t_edge[i].val,t_edge[i].y));
            }
        }
    }
}

int cal(int s,int t,int k)
{
    priority_queue<p,vector<p>,greater<p> >que;
    while(!que.empty())que.pop();
    que.push(p(f[s],s));
    memset(ans,0x3f,sizeof(ans));
    int cnt = 0;
    if(s == t)k++;
    while(!que.empty())
    {
        p tmp = que.top();
        que.pop();
        int now = tmp.second;
        int cost = tmp.first - f[now];
        if(now == t)
        {
            cnt++;
            if(cnt == k)return cost;
        }
        for(int i=next[now];i!=-1;i=edge[i].next)
        {
            que.push(p(cost+edge[i].val+f[edge[i].y],edge[i].y));
        }
    }
    return -1;
}

int main()
{
    scanf("%d%d",&n,&m);
    memset(next,-1,sizeof(next));
    memset(t_next,-1,sizeof(t_next));
    for(int i=1;i<=m;i++)
    {
        int u,v,k;
        scanf("%d%d%d",&u,&v,&k);
        add(u,v,k);
    }
    int s,t,k;
    scanf("%d%d%d",&s,&t,&k);
    get_f(t);
    printf("%d\n",cal(s,t,k));
}


Remmarguts' Date POJ - 2449 (A*搜索|k短路)

原文地址:https://www.cnblogs.com/iwannabe/p/10609823.html

时间: 2024-10-12 11:44:16

Remmarguts' Date POJ - 2449 (A*搜索|k短路)的相关文章

poj 2449 Remmarguts&#39; Date A*+spfa求第k短路

题意: 经典的第k短路,A*算法的经典应用之一. 分析: A*,已走的路程g+到终点的最短距离为启发函数,搜索过程中不判重,第k次到t节点时就求出了第k短路. 代码: //poj 2449 //sep9 #include <iostream> #include <queue> using namespace std; const int maxN=1024; const int maxM=100024; int n,m,s,t,k,e,ne; int head[maxN],nhea

POJ 2449 Remmarguts&#39; Date ( Dijkstra + A* 求解第K短路 )

#include <iostream> #include <cstring> #include <queue> #include <fstream> using namespace std; #define E 100005 #define V 1005 #define INF 1 << 30 int heads[V], r_heads[V]; int dists[V]; bool visits[V]; int nEdgeNum, nNodeNu

POJ 2449 求第K短路

第一道第K短路的题目 QAQ 拿裸的DIJKSTRA + 不断扩展的A* 给2000MS过了 题意:大意是 有N个station 要求从s点到t点 的第k短路 (不过我看题意说的好像是从t到s 可能是出题人写错了) 从这题中还真的学到了很多1.第k短路的算法 A* 还有用边表实现dij (注:以下部份资料来源于网上)所谓A*就是启发是搜索 说白了就是给搜索一个顺序使得搜索更加合理减少无谓的搜索. 如何来确定搜索的顺序?..也就是用一个值来表示 这个值为f[n]..每次搜索取f[x]最小的拓展 那

POJ 2449(求k短路,A*)

题目:求s到t的第k短路. 思路:网上是清一色的A*算法,所以学习了一下.所谓Astar算法其实就是启发式的bfs.这里设置了一个估价函数h,结合当前位置的最短路和到终点的估计最短路长度来选择下一个要扩展的节点(dijkstra算法对于所有的点的h值可以视为是一样的,所以下一个扩展的节点只与当前的最短路g有关).这个h的值越接近手记最短路越好,但是不能少于实际最短路(否则会错误),假设h值就是实际最短路的值,那么这个Astar算法可以一次找到最短路,相对的,如果h比实际值稍大,那么仍然可以去掉很

poj 2449 A*求k短路

A*的入门题目,需要注意的是当图中只有一个点的时候k短路是不存在的. 1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <queue> 5 using namespace std; 6 7 const int INF = 0x3f3f3f3f; 8 const int N = 1001; 9 const int M = 100000; 10 int head[N

POJ——T 2449 Remmarguts&#39; Date

http://poj.org/problem?id=2449 Time Limit: 4000MS   Memory Limit: 65536K Total Submissions: 30754   Accepted: 8394 Description "Good man never makes girls wait or breaks an appointment!" said the mandarin duck father. Softly touching his little

POJ 2449 Remmarguts&#39; Date (A*搜索求K短路)

传送门 这是一道裸的K短路的问题,我们将会用A*解决. 我们设计估值函数h的时候可以像这样想.因为h(n) <= h*(n)而且要尽量接近h*(n),所以我们想到,可以求一个从目标节点到其余节点的最短路,这个一定是小于等于实际值的.然后就用A*从起点开始搜索,找到一个节点v,就使cnt[v]加1.当cnt[v] > k时就可以剪枝了,因为这一定不再K短路的路线上了.很好通过反证法得到证明.当目标节点被搜索到了第k次的时候就可以结束搜索了. 要注意这道题有一个很坑的地方,就是若给出的起点=终点,

(最短路+A*搜索)POJ 2449 - Remmarguts&#39; Date

题意: 给一个DAG,要求s到t的第K短路,很经典的问题. 分析: 我们可以看到k<=1000,这个值不是很大,我可以想到直接bfs走遍所有情况,最多也就有1000中情况,但是1000个点显然会M. 既然是要求k短路,也就是说最终计算出来的到达t的花费必然是递增的,也就是说我们在搜索的时候肯定要用到优先队列. 这时应该很明显了,必然需要A*搜索,但是A*的预估函数依然是个问题,我想了很久没有想到,后来偶然在一本书上发现了这题. 书上的处理是用dijsktra预处理每点到t的最短路,就是每个状态到

POJ 2449 Remmarguts&#39; Date ( 第 k 短路 &amp;&amp; A*算法 )

题意 : 给出一个有向图.求起点 s 到终点 t 的第 k 短路.不存在则输出 -1 #include<stdio.h> #include<string.h> #include<queue> #include<algorithm> using namespace std; const int INF = 0x3f3f3f3f; const int maxn = 1024; const int maxm = 100008; struct EDGE{ int v