分層圖最短路問題

分層圖最短路是指在可以進行分層圖的圖上解決最短路問題。

一般模型是:

在圖上,有k次機會可以直接通過一條邊,問起點與終點之間的最短路徑。

基本介紹

  • 中文名:分層圖最短路問題
  • 領域:計算機科學
概念:,模板,Input,Output,常規算法分析,正規解法:,

概念:

分層圖最短路是指在可以進行分層圖的圖上解決最短路問題。
一般模型是:
在圖上,有k次機會可以直接通過一條邊,問起點與終點之間的最短路徑。

模板

首先看一個問題:
在你的強力援助下,PCY 成功完成了之前的所有任務,他覺得,現在正是出去浪的大好時光。於是,他來到高速公路上,找到一輛摩的前往幾千公里以外他心儀的那家黃燜雞米飯。由於 PCY 的品味異於常人,途經幾百個城市的黃燜雞米飯他都不屑一顧,他只願意前往他心中最好的那家,但是為了一碗二十塊錢的黃燜雞米飯,他不願意花上幾千塊的路費,他希望路費儘量少。高速路上的警察叔叔被他的行為所打動,於是在多方協調下,最多 K 條城市之間的高速收費站願意免費為 PCY 放行(可以任意選擇)。
顯然,PCY 已經筋疲力盡,不想再動用自己的數學天才來計算他可以花費的最小路費,因此他希望你可以幫他最後一次,他說他可以請你吃大碗的黃燜雞米飯,還可以加一瓶豆奶。
現在給你 N 個城市 (編號為0 …N - 1 ),M 條道路,和每條高速公路的花費Wi ,以及題目所描述的 K。PCY 想從城市 S 到城市 T ,因為他對 T 城市的黃燜雞米飯情有獨鐘。

Input

第一行,三個整數 N ,M ,K ,如題意所描述
第二行,兩個整數 S ,T ,代表出發城市和目標城市編號
接下來 M 行,每行三個整數 X ,Y ,W ,代表 X 和 Y 城市之間的高速公路收費為 W 元

Output

共一行 ,輸出一個整數 ,代表PCY 最少需要花費的路費。

常規算法分析

我們擁有k次機會可以免費通過,所以我們可以設dis【i】【j】表示在還剩j次免花費機會的情況下到i的最小花費,然後在圖上進行一次SPFA,對dis【T】【i】取min即可
代碼:
#include<iostream>#include<cstring>#include<cstdlib>#include<cstdio>#include<cmath>#include<queue>using namespace std;const int MAXN=20010;const int INF=0x3f3f3f3f;struct node{    int next;    int to;    int w;} t[MAXN*10];bool vis[MAXN];int head[MAXN],num;int dis[MAXN][11];int n,m,k;int S,T,ans;void add(int x,int y,int z){    t[ ++num ].next=head[ x ];    t[ num ].to=y;    t[ num ].w=z;    head[ x ]=num;}void spfa( ){    queue<int> q;    int x;    q.push( S );    vis[ S ]=1;    while( !q.empty() )    {        x=q.front();        q.pop();        vis[ x ]=0;        for(int i=head[ x ],y; i ; i=t[ i ].next)        {            y=t[ i ].to;            if( dis[ x ][ k ]+t[ i ].w<dis[ y ][ k ] )            {                dis[ y ][ k ]=dis[ x ][ k ]+t[ i ].w;                if( !vis[ y ] )   vis[ y ]=1,q.push( y );            }            for(int j=k-1; j>=0; j--)                if( dis[ x ][ j ]+t[ i ].w<dis[ y ][ j ] || dis[ x ][ j+1 ]<dis[ y ][ j ] )                {                    dis[ y ][ j ]=min( min(dis[ x ][ j ]+t[ i ].w,dis[ x ][ j+1 ]),dis[ y ][ j ] );                    if( !vis[ y ] )   vis[ y ]=1,q.push( y );                }        }    }}int main(){    int x,y,z;    memset( dis,INF,sizeof dis);    scanf("%d%d%d",&n,&m,&k);    scanf("%d%d",&S,&T);    for(int i=0; i<=k; i++)   dis[ S ][ i ]=0;    for(int i=1; i<=m; i++)    {        scanf("%d%d%d",&x,&y,&z);        add( x,y,z ),add( y,x,z );    }    spfa();    ans=INF;    for(int i=0; i<=k; i++)   ans=min( ans,dis[ T ][ i ] );    printf("%d\n",ans);    return 0;}

正規解法:

我們可以將這張圖分為k層,在每一層之間建立邊權為0的邊,這樣就能夠達到目的
代碼:
#include<iostream>#include<cstring>#include<cstdlib>#include<cstdio>#include<cmath>#define rg register#define ls 2*k#define rs 2*k+1using namespace std;const int MAXN=5000010;const int INF=0x3f3f3f3f;struct node{    int next;    int to;    int w;} t[MAXN];struct Heap{    int a[MAXN],dist[MAXN];    int tail;    void clear()    {        tail=0;    }    void Swap(int x,int y)    {        swap( a[ x ],a[ y ] );        swap( dist[ x ],dist[ y ] );    }    void insert(rg int id,rg int d)    {        a[ ++tail ]=id,dist[ tail ]=d;        int tmp=tail;        while( tmp>=2 )        {            if( dist[ tmp ]<dist[ tmp/2 ] )            {                Swap( tmp,tmp/2 );                tmp=tmp/2;            }            else   break ;        }    }    void update(rg int k)    {        int tmp=k;        if( ls<=tail && dist[ ls ]<=dist[ tmp ] )   tmp=ls;        if( rs<=tail && dist[ rs ]<=dist[ tmp ] )   tmp=rs;        if( tmp!=k )        {            Swap( k,tmp );            update( tmp );        }    }    int top( )    {        return a[ 1 ];    }    void pop( )    {        a[ 1 ]=a[ tail ],dist[ 1 ]=dist[ tail-- ];        if( tail<=1 )   return ;        update( 1 );    }    int empty( )    {        return tail;    }} q;bool vis[MAXN];int head[MAXN],num;int dis[MAXN];int n,m,k;int S,T,ans=INF;inline int gi(){    int x=0,f=1;    char ch=getchar();    while (ch<'0' || ch>'9') {if (ch=='-') f=-1;ch=getchar();}    while (ch>='0' && ch<='9') {x=x*10+ch-'0';ch=getchar();}    return x*f;}inline void add(int x,int y,int z){    t[ ++num ].next=head[ x ];    t[ num ].to=y;    t[ num ].w=z;    head[ x ]=num;}inline void dijkstra( ){    int  x;    memset( dis,INF,sizeof dis);    q.clear();    dis[ S ]=0;    q.insert( S,0 );    while( q.empty() )    {        x=q.top(),q.pop();        if( vis[ x ] )   continue ;        vis[ x ]=1;        for(rg int i=head[ x ],y; i ;i=t[ i ].next )        {            y=t[ i ].to;            if( dis[ y ]>dis[ x ]+t[ i ].w && !vis[ y ] )            {                dis[ y ]=dis[ x ]+t[ i ].w;                q.insert( y,dis[ y ] );            }        }    }}int main(){    int x,y,z,t0,t1,t2;   n=gi(),m=gi(),k=gi(),S=gi(),T=gi();    for(int i=1; i<=m; i++)    {       x=gi(),y=gi(),z=gi();        for(int j=0;j<=k;j++)        {            add( x+n*j,y+n*j,z ),add( y+n*j,x+n*j,z );            if( j<k )   add( x+n*j,y+n*(j+1),0 ),add( y+n*j,x+n*(j+1),0 );        }    }    dijkstra();    for(int i=0; i<=k; i++)   ans=min( ans,dis[ T+i*n ] );    printf("%d\n",ans);    return 0;}

相關詞條

熱門詞條

聯絡我們