2011-08-26 145 views
24

查找圖中兩點之間的最短路徑是一個經典算法問題,其中有很多很好的答案(Dijkstra's algorithmBellman-Ford等)。我的問題是,節點s和t以及值k,找到s和t之間的第k個最短路徑。如果有多條相同長度的路徑都是第k個最短的路徑,那麼算法返回它們中的任何一個都可以。找到第k個最短路徑?

我懷疑這個算法可能可以在多項式時間完成,但我知道可能會減少從longest path problem,這將使其NP-hard。

有沒有人知道這樣的算法,或減少,表明它是NP難?

+0

HTTP://www.springerlink .com/content/pl0054nt2d0d2u3t/ –

+0

你幾乎肯定是指一般的第k個最短路徑問題,但是如果你對邊緣不相交的路徑感興趣,你可以使用Edmonds-Karp算法找到它們:http:// www .mat.uc.pt /〜eqvm/OPP/KSPP/KSPP.html – IVlad

+4

僅供參考:Yen的算法適用於只考慮簡單路徑的情況,而Eppstein算法適用於允許非簡單路徑的情況(例如,允許路徑多次重新訪問同一節點)。切線方向,如果你想*嚴格*第二條最短路徑(我知道你說的是相反的),非簡單版本在P中,簡單的無向版本在P中(Krasikov-Noble/Zhang-Nagamochi),而簡單定向版本是NP-hard(Lalgudi-Papaefthymiou)。另外,對於它的價值,我還沒有看到Yen的算法有很好的描述,但我想要一個! – daveagp

回答

10

您正在尋找Yen的尋找K最短路徑的算法。那麼最短的路徑將成爲該組中的最後一條路徑。

這是Yen's算法的implementation

這裏是描述它的original paper

+0

對不起,我沒有時間描述它,現在寫在這篇文章中。但如果您無法訪問該文件,我可以稍後再做。 – tskuzzy

-1

儘管該問題有一個有效的接受答案,但該答案通過提供示例工作代碼來解決實施問題。查找第k最短路徑此處的有效代碼:

//時間複雜度:O(V ķ(V * logV + E))

using namespace std; 

typedef long long int ll; 
typedef short int i16; 
typedef unsigned long long int u64; 
typedef unsigned int u32; 
typedef unsigned short int u16; 
typedef unsigned char u8; 

const int N = 128; 

struct edge 
{ 
    int to,w; 
    edge(){} 
    edge(int a, int b) 
    { 
     to=a; 
     w=b; 
    } 
}; 

struct el 
{ 
    int vertex,cost; 
    el(){} 
    el(int a, int b) 
    { 
     vertex=a; 
     cost=b; 
    } 
    bool operator<(const el &a) const 
    { 
     return cost>a.cost; 
    } 
}; 

priority_queue <el> pq; 

vector <edge> v[N]; 

vector <int> dist[N]; 

int n,m,q; 

void input() 
{ 
    int i,a,b,c; 
    for(i=0;i<N;i++) 
     v[i].clear(); 
    for(i=1;i<=m;i++) 
    { 
     scanf("%d %d %d", &a, &b, &c); 
     a++; 
     b++; 
     v[a].push_back(edge(b,c)); 
     v[b].push_back(edge(a,c)); 
    } 
} 

void Dijkstra(int starting_node, int ending_node) 
{ 
    int i,current_distance; 
    el curr; 
    for(i=0;i<N;i++) 
     dist[i].clear(); 
    while(!pq.empty()) 
     pq.pop(); 
    pq.push(el(starting_node,0)); 
    while(!pq.empty()) 
    { 
     curr=pq.top(); 
     pq.pop(); 
     if(dist[curr.vertex].size()==0) 
      dist[curr.vertex].push_back(curr.cost); 
     else if(dist[curr.vertex].back()!=curr.cost) 
      dist[curr.vertex].push_back(curr.cost); 
     if(dist[curr.vertex].size()>2) 
      continue; 
     for(i=0;i<v[curr.vertex].size();i++) 
     { 
      if(dist[v[curr.vertex][i].to].size()==2) 
       continue; 
      current_distance=v[curr.vertex][i].w+curr.cost; 
      pq.push(el(v[curr.vertex][i].to,current_distance)); 
     } 
    } 
    if(dist[ending_node].size()<2) 
     printf("?\n"); 
    else 
     printf("%d\n", dist[ending_node][1]); 
} 

void solve() 
{ 
    int i,a,b; 
    scanf("%d", &q); 
    for(i=1;i<=q;i++) 
    { 
     scanf("%d %d", &a, &b); 
     a++; 
     b++; 
     Dijkstra(a,b); 
    } 
} 

int main() 
{ 
    int i; 
    for(i=1;scanf("%d %d", &n, &m)!=EOF;i++) 
    { 
     input(); 
     printf("Set #%d\n", i); 
     solve(); 
    } 
    return 0; 
}