题目链接:http://poj.org/problem?id=2449

Time Limit: 4000MS Memory Limit: 65536K

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

题意:

给出 $N$ 个顶点,$M$ 条有向边,求从起点 $S$ 到终点 $T$ 的第 $K$ 短路的长度,路径允许重复经过点和边。

(如果不存在第 $k$ 短路则输出 $-1$。其实不难知道如果从 $S$ 到 $T$ 的某条路径上存在一个环,则必然存在第 $k$ 短路,否则就有可能没有第 $k$ 短路)

(有一个需要注意的点是,此处当 $S=T$ 时,认为最短路径不是零)

题解:

根据优先队列优化Dijkstra算法,我们知道,优先队列里面的可能存在多个元素 $(x,d_1[x]),(x,d_2[x]), \cdots$,同时代表着某个节点 $x$ 以及起点到 $x$ 的某条路径的长度。

当从优先队列中第一次取出 $x$ 时,起点到 $x$ 的最短路长度已经得到,那么后续再取出节点 $x$ 显然就是一些次短路径。

由此我们可以想到使用优先队列BFS

起初优先队列中只存在元素 $(S,0)$,不断从优先队列中取出 $d[x]$ 最小的 $(x,d[x])$,然后沿着从 $x$ 出发的每条有向边 $edge(x,y)$ 都进行扩展,将新的元素 $(y,d[y]=d[x]+w(x,y))$ 入队(本题允许重复经过点和边)。

不难证明,某个状态 $(x,d_1[x])$ 第一次从优先队列中被取出时,就得到了从初态到它的最小代价 $d[x]$。因为此时队列中所有其他状态的代价都大于等于 $d[x]$,是不可能再返回来更新 $d[x]$ 的。

然后,如果按照普通的优先队列BFS做法(即优先队列优化Dijkstra算法),往后若再从队列内取出另一个元素 $(x,d_2[x])$,会将其直接忽略,因为必然不是最优解。

那么,不难想到在本题的优先队列BFS做法中,第 $i$ 次从优先队列中取出的元素 $(x,d_i[x])$,其 $d_i[x]$ 便是从起点到 $x$ 的第 $i$ 短路长度。

所以,最终当终点 $T$ 从队列中第 $K$ 次出队时,便求得了答案。

这样算法最坏的时间复杂度为 $O(K(N+M)log(N+M))$。

MLE代码:

#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
using namespace std;
typedef pair<int,int> pii;
const int maxn=;
int n,m,S,T,K; struct Edge{
int v,w;
Edge(){}
Edge(int _v,int _w) {
v=_v, w=_w;
}
};
vector<Edge> E[maxn]; priority_queue< pii, vector<pii>, greater<pii> > Q;
int cnt[maxn];
int bfs()
{
memset(cnt,,sizeof(cnt));
Q.push(make_pair(,S));
while(!Q.empty())
{
int x=Q.top().second, d=Q.top().first; Q.pop(); cnt[x]++;
if(cnt[T]==K) return d;
for(int k=;k<E[x].size();k++)
{
int y=E[x][k].v, w=E[x][k].w;
if(cnt[y]<K) Q.push(make_pair(d+w,y));
}
}
return -;
} int main()
{
cin>>n>>m;
for(int i=,u,v,w;i<=m;i++)
{
scanf("%d%d%d",&u,&v,&w);
E[u].push_back(Edge(v,w));
}
cin>>S>>T>>K;
if(S==T) K++;
cout<<bfs()<<endl;
}

交了一发,得到MLE $\times 1$,应该是优先队列内存的元素太多了……

A*优化:

我们知道,A*用一个估价函数 $f(x)$ 来估计当前状态到目标状态所需代价。

在本题中,实际代价 $g(x)$ 即代表:第 $k$ 短路中从 $x$ 到 $T$ 的实际距离。

显然,相应的我们可以设 $f(x)$ 代表:最短路中从 $x$ 到 $T$ 的实际距离。

这样一来,必然满足条件 $f(x) \le g(x)$,正确性得以保证。

优先队列内原本存储的是 $(x,d[x])$,现在变为 $(x,d[x]+f(x))$。

A*算法的时间复杂度上界一样是 $O(K(N+M)log(N+M))$,但由于估价函数 $f(x)$ 的作用,很多节点访问次数远小于 $k$,是有较明显的加速的(相应的优先队列内存储的元素会大幅度减少,避免MLE)。

AC代码:

#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
using namespace std;
typedef pair<int,int> pii;
const int maxn=;
const int INF=0x3f3f3f3f;
int n,m,S,T,K; struct Edge{
int v,w;
Edge(){}
Edge(int _v,int _w) {
v=_v, w=_w;
}
};
vector<Edge> E[maxn],fE[maxn];
priority_queue< pii, vector<pii>, greater<pii> > Q; int f[maxn];
bool vis[maxn];
void dijkstra()
{
memset(f,0x3f,sizeof(f));
memset(vis,,sizeof(vis));
f[T]=;
Q.push(make_pair(,T));
while(Q.size())
{
int u=Q.top().second; Q.pop();
if(vis[u]) continue;
vis[u]=;
for(int i=;i<fE[u].size();i++)
{
int v=fE[u][i].v, w=fE[u][i].w;
if(vis[v]) continue;
if(f[v]>f[u]+w)
{
f[v]=f[u]+w;
Q.push(make_pair(f[v],v));
}
}
}
} int cnt[maxn];
int bfs()
{
memset(cnt,,sizeof(cnt));
Q.push(make_pair(,S));
while(!Q.empty())
{
int x=Q.top().second, d=Q.top().first; Q.pop(); cnt[x]++;
if(cnt[T]==K) return d;
for(int k=;k<E[x].size();k++)
{
int y=E[x][k].v, w=E[x][k].w;
if(cnt[y]<K) Q.push(make_pair(d+w,y));
}
}
return -;
} int A_star()
{
memset(cnt,,sizeof(cnt));
Q.push(make_pair(+f[S],S));
while(Q.size())
{
int u=Q.top().second;
int d=Q.top().first-f[u];
Q.pop(); cnt[u]++;
if(cnt[T]==K) return d;
for(int i=,v,w;i<E[u].size();i++)
{
v=E[u][i].v, w=E[u][i].w;
if(cnt[v]<K) Q.push(make_pair(d+w+f[v],v));
}
}
return -;
} int main()
{
cin>>n>>m;
for(int i=,u,v,w;i<=m;i++)
{
scanf("%d%d%d",&u,&v,&w);
E[u].push_back(Edge(v,w));
fE[v].push_back(Edge(u,w));
}
cin>>S>>T>>K;
if(S==T) K++;
dijkstra();
cout<<A_star()<<endl;
}

POJ 2449 - Remmarguts' Date - [第k短路模板题][优先队列BFS]的更多相关文章

  1. poj 2449 Remmarguts' Date (k短路模板)

    Remmarguts' Date http://poj.org/problem?id=2449 Time Limit: 4000MS   Memory Limit: 65536K Total Subm ...

  2. poj 2449 Remmarguts' Date 第k短路 (最短路变形)

    Remmarguts' Date Time Limit: 4000MS   Memory Limit: 65536K Total Submissions: 33606   Accepted: 9116 ...

  3. poj 2449 Remmarguts' Date(K短路,A*算法)

    版权声明:本文为博主原创文章.未经博主同意不得转载. https://blog.csdn.net/u013081425/article/details/26729375 http://poj.org/ ...

  4. POJ 2449 Remmarguts' Date ( 第 k 短路 && A*算法 )

    题意 : 给出一个有向图.求起点 s 到终点 t 的第 k 短路.不存在则输出 -1 #include<stdio.h> #include<string.h> #include ...

  5. 【POJ】2449 Remmarguts' Date(k短路)

    http://poj.org/problem?id=2449 不会.. 百度学习.. 恩. k短路不难理解的. 结合了a_star的思想.每动一次进行一次估价,然后找最小的(此时的最短路)然后累计到k ...

  6. 【POJ】2449.Remmarguts' Date(K短路 n log n + k log k + m算法,非A*,论文算法)

    题解 (搬运一个原来博客的论文题) 抱着板题的心情去,结果有大坑 就是S == T的时候也一定要走,++K 我发现按照论文写得\(O(n \log n + m + k \ log k)\)算法没有玄学 ...

  7. [poj2449]Remmarguts' Date(K短路模板题,A*算法)

    解题关键:k短路模板题,A*算法解决. #include<cstdio> #include<cstring> #include<algorithm> #includ ...

  8. K短路模板POJ 2449 Remmarguts' Date

      Time Limit: 4000MS   Memory Limit: 65536K Total Submissions:32863   Accepted: 8953 Description &qu ...

  9. poj 2449 Remmarguts' Date(第K短路问题 Dijkstra+A*)

    http://poj.org/problem?id=2449 Remmarguts' Date Time Limit: 4000MS   Memory Limit: 65536K Total Subm ...

随机推荐

  1. 把linux的man手册转化为windows下可读的格式

    原文链接: http://www.linux521.com/2009/system/200904/1542.html 把linux的man手册转化为windows下可读的格式 我也是一个Linux学习 ...

  2. Cannot attach the file as database

    Cannot attach the file as database这个异常是在EF的code frist里经常出现的,解决方法很简单,只要重新启动一下V11实例即可. CMD> sqlloca ...

  3. Java代码里利用Fiddler抓包调试设置

    Fiddler启动时已经将自己注册为系统的默认代理服务器,应用程序在访问网络时会去获取系统的默认代理,如果需要捕获java访问网络时的数据,只需要在启动java程序时设置代理服务器为Fiddler即可 ...

  4. [svc]runinit管理多进程

    runinit启动小程序测试 与Supervisord类似的工具包括monit, daemontools和runit. 我还发现个神器,专门针对单容器启动多进程的神器s6: https://githu ...

  5. python thrift使用实例

    前言 Apache Thrift 是 Facebook 实现的一种高效的.支持多种编程语言的远程服务调用的框架.本文将从 Python开发人员角度简单介绍 Apache Thrift 的架构.开发和使 ...

  6. 物联网架构成长之路(3)-EMQ消息服务器了解

    1. 了解 物联网最基础的就是通信了.通信协议,物联网协议好像有那么几个,以前各个协议都有优劣,最近一段时间,好像各大厂商都采用MQTT协议,所以我也不例外,不搞特殊,采用MQTT协议,选定了协议,接 ...

  7. 简单的topK问题

    /************************************************************************/ /* 求一组数据中的top(K)问题,这是一个经典 ...

  8. python中关于round函数的小坑

    这个一直都想写,但是因为这个点比较小,所以一直懒得动手.不过还是补上吧,留着早晚是个祸害. round函数很简单,对浮点数进行近似取值,保留几位小数.比如 >>> round(10. ...

  9. iOS开发 关于启动页和停留时间的设置

    引言: 在开发一款商业App时,我们大都会为我们的App设置一个启动页. 苹果官方对于iOS启动页的设计说明: 为了增强应用程序启动时的用户体验,您应该提供一个启动图像.启动图像与应用程序的首屏幕看起 ...

  10. 【iCore4 双核心板_ARM】例程五:SYSTICK定时器 实验——定时点亮LED

    实验原理: 通过STM32的三个GPIO口驱动三色LED的三个通道,设定GPIO为推挽输出模式,采 用灌电流方式与LED连接,输出高电平LED灭,输出低电平LED亮,通过系统定时器实现 1s定时,每秒 ...