POJ2449Remmarguts' Date(A*算法求第K小路)

Remmarguts‘ Date

Time Limit: 4000MS   Memory Limit: 65536K
Total Submissions: 21084   Accepted: 5740

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

Source

POJ Monthly,Zeyuan Zhu

该题意所给的是有向边。求的是从起点S到终点T的第K最短路。

解题:因为A*算法是以最快的方法求出一条最短路,所以这里第 i 次算出一条路到终点那么一定是第i最短路。

那么我们现在的任务关建就是设计A*中的估价F[i],而F[i]=G[i]+H[i],G[i]表示的是从起始点到当前点i的路径总和,这个可以在过程中求出;H[i]表示的是从当前点到终点的路径总和,每次从开放集合中取出最小F[i]的点,这个可以用优先队列表示开放集合。明白这里之后,我们的任务就是要算出每个点到终点的H值,那么这样我们可以建一个反向图,从起点到达每一个点的最短路也就算完成了求出每个点的H值。

注意两点:1.每个点我们最多只求出K条路,有大于K条路就不必再往下走了,因为当前点的第K+1条最短路到达终点时一定不在终点的K条最短路之列。

2.有的点是走不到终点的,那么我们就不用考虑这一类的点,可以列出黑名单里,而这个判断就是通过H[i]值。

这样我们便顺利的完成了这一类题。

#include<stdio.h>
#include<iostream>
#include<queue>
#include<vector>
using namespace std;
#define inf 99999999
#define N 1100
typedef struct nnn
{
    int F,G,s;
    friend bool operator<(nnn a,nnn b)
    {
        return a.F>b.F;
    }
}PATH;
typedef struct nn
{
    int v,w;
}node;
vector<node>map[N],tmap[N];
int H[N];
void findH(int s)
{
    queue<int>q;
    int inq[N]={0};
    q.push(s); inq[s]=1; H[s]=0;
    while(!q.empty())
    {
        s=q.front(); q.pop(); inq[s]=0;
        int m=tmap[s].size();
        for(int i=0;i<m;i++)
        {
            int j=tmap[s][i].v;
            if(H[j]>tmap[s][i].w+H[s])
            {
                H[j]=tmap[s][i].w+H[s];
                if(!inq[j])
                inq[j]=1,q.push(j);
            }
        }
    }
}
int Astar(int st,int end,int K)
{
    priority_queue<PATH>q;
    PATH p,tp;
    int k[N]={0};
    findH(end);
    if(H[st]==inf)return -1;
    p.s=st; p.G=0; p.F=H[st];
    q.push(p);
    while(!q.empty())
    {
        p=q.top(); q.pop();
        k[p.s]++;
        if(k[p.s]>K)continue;//每个点最多走K次,超过K条路不必走
        if(p.s==end&&k[end]==K) return p.F;
        int m=map[p.s].size();
        for(int i=0;i<m;i++)
        {
            int j=map[p.s][i].v;
            if(H[j]!=inf)//表明当前点不能通向终点,就不用加入队列
            {
                tp.G=p.G+map[p.s][i].w;
                tp.F=H[j]+tp.G;
                tp.s=j;
                q.push(tp);
            }
        }
    }
    return -1;
}
int main()
{
    int n,m,S,T,K,a,b,t;
    node p;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        {
            map[i].clear(); tmap[i].clear(); H[i]=inf;
        }

        while(m--)
        {
            scanf("%d%d%d",&a,&b,&t);
            p.v=b; p.w=t; map[a].push_back(p);
            p.v=a;   tmap[b].push_back(p);//反建一个地图求H
        }
        scanf("%d%d%d",&S,&T,&K);
        if(S==T)K++;
        printf("%d\n",Astar(S,T,K));
}

POJ2449Remmarguts' Date(A*算法求第K小路)

时间: 2024-10-03 11:25:00

POJ2449Remmarguts' Date(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

A* 算法求第 K 短路

一种具有 \(f(n)=g(n)+h(n)\) 策略的启发式算法能成为 A* 算法的充分条件是: 搜索树上存在着从起始点到终了点的最优路径. 问题域是有限的. 所有结点的子结点的搜索代价值 \(>0\). \(h(n) \le h^\ast (n)\) (\(h^\ast (n)\) 为实际问题的代价值). Remmarguts' Date 求 S 到 T 的第 K 短路. 思路: (1) 将有向图的所有边反向,以原终点T为源点,求解T到所有点的最短距离. (2) 新建一个优先队列,将源点S加入

&lt;学习笔记&gt; A*算法求第k短路

一条前往题面的隧道 简洁题面 第一行给出N(点数),M(边数)(1 <= N <= 1000, 0 <= M <= 100000).. 下面的M行每行给出三个数Ai,Bi,Ti,表示从A到B有一条权值为T的单向边. 最后给出S,T,K,表示求S到T的第K短路. special: 起点与终点相同时,S–>S (d=0) 不能算作一条路. 题目会给出多组数据. 即使有好几条路到T的距离都相同,它们仍被记为不同的路. 正解 A*算法 记g[i]为起点s到i的距离,h[i] (期望值

aStar算法求第k短路

A*的概念主意在于估计函数,f(n)=g(n)+h(n),f(n)是估计函数,g(n)是n节点的当前代价,h(n)是n节点的估计代价:而实际中,存在最优的估计函数f'(n)=g'(n)+h'(n),那么显然我们在A*的估计中,h(n)<=h'(n),否则你将搜不到最优解:(g(n)>=g'(n)我还不怎么清楚为什么啊,大多数情况是g(n)=g'(n),这个可以不用管吧..) 求s->t的第k短路, dist[x]为x->t的最短路 (这个只要反向建边,然后一次spfa,求出任意点到

poj 2449 Remmarguts&#39; Date 求第k短路 Astar算法

=.=好菜 #include <iostream> #include <cstdio> #include <string.h> #include <cstring> #include <queue> using namespace std; const int N = 1e3+10; const int M = 100000+10; typedef long long ll; const ll INF = 1e15; int n,m,head[N

普林斯顿大学算法课 Algorithm Part I Week 3 求第K大数 Selection

问题 给定N个元素的数组,求第k大的数. 特例当k=0时,就是求最大值,当k=N-1时,就是求最小值. 应用顺序统计求top N排行榜 基本思想 使用快速排序方法中的分区思想,使得a[k]左侧没有更小的数,右侧没有更大的数 性能 快速选择算法的复杂度是N. 最坏情况下的复杂度是1/2N^2,但是可以通过预先洗牌来防止出现最坏情况 public static Comparable select(Comparable[] a, int k) { StdRandom.shuffle(a); int l

普林斯顿公开课 算法3-2:求第k大的数

问题 给定N个元素的数组,求第k大的数. 特例 当k=0时,就是求最大值,当k=N-1时,就是求最小值. 应用 顺序统计 求top N排行榜 基本思想 使用快速排序方法中的分区思想,使得a[k]左侧没有更小的数,右侧没有更大的数 性能 快速选择算法的复杂度是N. 最坏情况下的复杂度是1/2N^2,但是可以通过预先洗牌来防止出现最坏情况 代码 public class QuickSort { // 对区间 [start, end) 进行分区 public static int partition(

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次的时候就可以结束搜索了. 要注意这道题有一个很坑的地方,就是若给出的起点=终点,

算法导论学习之线性时间求第k小元素+堆思想求前k大元素

对于曾经,假设要我求第k小元素.或者是求前k大元素,我可能会将元素先排序,然后就直接求出来了,可是如今有了更好的思路. 一.线性时间内求第k小元素 这个算法又是一个基于分治思想的算法. 其详细的分治思路例如以下: 1.分解:将A[p,r]分解成A[p,q-1]和A[q+1,r]两部分.使得A[p,q-1]都小于A[q],A[q+1,r]都不小于A[q]; 2.求解:假设A[q]恰好是第k小元素直接返回,假设第k小元素落在前半区间就到A[p,q-1]递归查找.否则到A[q+1,r]中递归查找. 3