【问题描述】
给出一个图G和指定的源点s、汇点t,求图中从点s到点t的第K短路。
【具体题目】 PKU2449(注意:本题有一个猥琐之处:不允许空路径。也就是当s等于t时要将K值加1)
【算法】
本题有一种最朴素的办法:改造Dijkstra,一开始路径(s, 0)(这里设路径(i, l)表示从s到i的一条长度为l的路径)入队。然后, 每次取队中长度最短的路径,该路径(i, l)出队,可以证明,若这是终点为i的路径第x次出队,该路径一定是图中从s到i的第x短路(若x>K则该路径已无用,舍弃)。然后从点i扩展,将扩展到的路径全部入队。这样直到终点为t的路径第K次出队即可。
该算法容易实现(借助priority_queue),但时间复杂度可能达到O(MK),需要优化。
优化:容易发现该算法其实有A*的思想,或者说,该算法 其实是所有结点的估价函数h()值均为0的A*算法。为了优化此题,需要将h()值改大。显然,h(i)值可以设为 从i到t的最短路径长度(容易证明它是一致的),然后g(i)=目前结点代表的路径长度,f(i)=g(i)+h(i),然后A*即可。
注意:更改路径条数应该在出队时更改,而不能在入队时更改,因为可能在该路径出队之前会有新的比它更短的路径入队。
代码(PKU2449):
给出一个图G和指定的源点s、汇点t,求图中从点s到点t的第K短路。
【具体题目】 PKU2449(注意:本题有一个猥琐之处:不允许空路径。也就是当s等于t时要将K值加1)
【算法】
本题有一种最朴素的办法:改造Dijkstra,一开始路径(s, 0)(这里设路径(i, l)表示从s到i的一条长度为l的路径)入队。然后, 每次取队中长度最短的路径,该路径(i, l)出队,可以证明,若这是终点为i的路径第x次出队,该路径一定是图中从s到i的第x短路(若x>K则该路径已无用,舍弃)。然后从点i扩展,将扩展到的路径全部入队。这样直到终点为t的路径第K次出队即可。
该算法容易实现(借助priority_queue),但时间复杂度可能达到O(MK),需要优化。
优化:容易发现该算法其实有A*的思想,或者说,该算法 其实是所有结点的估价函数h()值均为0的A*算法。为了优化此题,需要将h()值改大。显然,h(i)值可以设为 从i到t的最短路径长度(容易证明它是一致的),然后g(i)=目前结点代表的路径长度,f(i)=g(i)+h(i),然后A*即可。
注意:更改路径条数应该在出队时更改,而不能在入队时更改,因为可能在该路径出队之前会有新的比它更短的路径入队。
代码(PKU2449):
#include
<
iostream
>
#include < stdio.h >
#include < queue >
using namespace std;
#define re(i, n) for (int i=0; i<n; i++)
const int MAXN = 1500 , MAXM = 150000 , INF = ~ 0U >> 2 ;
struct edge {
int kk, len, next;
} ed[MAXM], ed2[MAXM];
int n, m, s, t, k_, hd[MAXN], tl[MAXN], hd2[MAXN], tl2[MAXN], h[MAXN], q[MAXN + 1 ], No[MAXN], res = - 1 ;
bool vst[MAXN];
struct qnode {
int i, g;
};
typedef priority_queue < qnode, vector < qnode > > pq;
pq z;
bool operator < (qnode q1, qnode q2)
{
return q1.g + h[q1.i] > q2.g + h[q2.i];
}
void init()
{
int a0, b0, l0;
scanf( " %d%d " , & n, & m);
re(i, n) hd[i] = tl[i] = hd2[i] = tl2[i] = - 1 ;
re(i, m) {
scanf( " %d%d%d " , & a0, & b0, & l0); a0 -- ; b0 -- ;
ed[i].kk = b0; ed[i].len = l0; ed[i].next = - 1 ;
if (hd[a0] == - 1 ) hd[a0] = tl[a0] = i; else tl[a0] = ed[tl[a0]].next = i;
ed2[i].kk = a0; ed2[i].len = l0; ed2[i].next = - 1 ;
if (hd2[b0] == - 1 ) hd2[b0] = tl2[b0] = i; else tl2[b0] = ed2[tl2[b0]].next = i;
}
scanf( " %d%d%d " , & s, & t, & k_); -- s; -- t; k_ += s == t;
}
void prepare()
{
re(i, n) {h[i] = INF; vst[i] = 0 ;} h[t] = 0 ; vst[t] = 1 ; q[ 0 ] = t;
int i, h0, j, h1;
for ( int front = 0 , rear = 0 ; ! ( ! front && rear == n || front == rear + 1 ); front == n ? front = 0 : front ++ ) {
i = q[front]; h0 = h[i];
for ( int p = hd2[i]; p != - 1 ; p = ed2[p].next) {
j = ed2[p].kk; h1 = h0 + ed2[p].len;
if (h1 < h[j]) {
h[j] = h1;
if ( ! vst[j]) {vst[j] = 1 ; if (rear == n) q[rear = 0 ] = j; else q[ ++ rear] = j;}
}
}
vst[i] = 0 ;
}
}
void solve()
{
qnode q0; q0.i = s; q0.g = 0 ; z.push(q0);
re(i, n) No[i] = 0 ;
int i, d0, j, d1;
while ( ! z.empty()) {
i = z.top().i; d0 = z.top().g; z.pop();
if (No[i] >= k_) continue ;
No[i] ++ ;
if (i == t && No[i] == k_) {res = d0; break ;}
for ( int p = hd[i]; p != - 1 ; p = ed[p].next) {
j = ed[p].kk; d1 = d0 + ed[p].len;
q0.i = j; q0.g = d1; z.push(q0);
}
}
}
void pri()
{
printf( " %d\n " , res);
}
int main()
{
init();
prepare();
solve();
pri();
return 0 ;
}
#include < stdio.h >
#include < queue >
using namespace std;
#define re(i, n) for (int i=0; i<n; i++)
const int MAXN = 1500 , MAXM = 150000 , INF = ~ 0U >> 2 ;
struct edge {
int kk, len, next;
} ed[MAXM], ed2[MAXM];
int n, m, s, t, k_, hd[MAXN], tl[MAXN], hd2[MAXN], tl2[MAXN], h[MAXN], q[MAXN + 1 ], No[MAXN], res = - 1 ;
bool vst[MAXN];
struct qnode {
int i, g;
};
typedef priority_queue < qnode, vector < qnode > > pq;
pq z;
bool operator < (qnode q1, qnode q2)
{
return q1.g + h[q1.i] > q2.g + h[q2.i];
}
void init()
{
int a0, b0, l0;
scanf( " %d%d " , & n, & m);
re(i, n) hd[i] = tl[i] = hd2[i] = tl2[i] = - 1 ;
re(i, m) {
scanf( " %d%d%d " , & a0, & b0, & l0); a0 -- ; b0 -- ;
ed[i].kk = b0; ed[i].len = l0; ed[i].next = - 1 ;
if (hd[a0] == - 1 ) hd[a0] = tl[a0] = i; else tl[a0] = ed[tl[a0]].next = i;
ed2[i].kk = a0; ed2[i].len = l0; ed2[i].next = - 1 ;
if (hd2[b0] == - 1 ) hd2[b0] = tl2[b0] = i; else tl2[b0] = ed2[tl2[b0]].next = i;
}
scanf( " %d%d%d " , & s, & t, & k_); -- s; -- t; k_ += s == t;
}
void prepare()
{
re(i, n) {h[i] = INF; vst[i] = 0 ;} h[t] = 0 ; vst[t] = 1 ; q[ 0 ] = t;
int i, h0, j, h1;
for ( int front = 0 , rear = 0 ; ! ( ! front && rear == n || front == rear + 1 ); front == n ? front = 0 : front ++ ) {
i = q[front]; h0 = h[i];
for ( int p = hd2[i]; p != - 1 ; p = ed2[p].next) {
j = ed2[p].kk; h1 = h0 + ed2[p].len;
if (h1 < h[j]) {
h[j] = h1;
if ( ! vst[j]) {vst[j] = 1 ; if (rear == n) q[rear = 0 ] = j; else q[ ++ rear] = j;}
}
}
vst[i] = 0 ;
}
}
void solve()
{
qnode q0; q0.i = s; q0.g = 0 ; z.push(q0);
re(i, n) No[i] = 0 ;
int i, d0, j, d1;
while ( ! z.empty()) {
i = z.top().i; d0 = z.top().g; z.pop();
if (No[i] >= k_) continue ;
No[i] ++ ;
if (i == t && No[i] == k_) {res = d0; break ;}
for ( int p = hd[i]; p != - 1 ; p = ed[p].next) {
j = ed[p].kk; d1 = d0 + ed[p].len;
q0.i = j; q0.g = d1; z.push(q0);
}
}
}
void pri()
{
printf( " %d\n " , res);
}
int main()
{
init();
prepare();
solve();
pri();
return 0 ;
}