分层图最短路是指在可以进行分层图的图上解决最短路问题。一般模型是:在图上,有k次机会可以直接通过一条边,问起点与终点之间的最短路径。—— 引自百度百科
模板题目:https://ac.nowcoder.com/acm/contest/884/J
https://www.luogu.org/problem/P4568
处理方法
网传所谓建图,DP两种方法,无非是写法不同,其本质都是建立多层图(个人见解)。
建图
建图时把原图复制k份,每份之间的边权应该置为0(意为使用一次免费机会)。从1层的s跑一遍dijkstra到k层的t。
void pre(int x,int y,int w) { for(int i=0;i<=k;i++) add(x+n*i,y+n*i,w), add(y+n*i,x+n*i,w); for(int i=0;i<k;i++) add(x+n*i,y+n*i+n,0), add(y+n*i,x+n*i+n,0); }
当然也完全可以用一个二维数组来存,方便好写,代码如下:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include<iostream> 2 #include<cstring> 3 #include<queue> 4 #define ll long long 5 using namespace std; 6 typedef pair<int,int> pir; 7 priority_queue<pir,vector<pir>,greater<pir> > q; 8 struct node 9 { 10 int nex,y,w; 11 }e[2002]; 12 int m,n,s,t,k; 13 int head[1001]; 14 int d[1001][1001]; 15 bool v[1001][1001]; 16 void add(int x,int y,int z) 17 { 18 e[++m].y=y; 19 e[m].w=z; 20 e[m].nex=head[x]; 21 head[x]=m; 22 } 23 void DJ() 24 { 25 memset(d,0x3f,sizeof(d)); 26 int x,j,num; 27 d[s][0]=0; 28 q.push(make_pair(0,s)); 29 while(q.size()) 30 { 31 x=q.top().second;q.pop(); 32 num=x/n;x%=n; 33 if(v[x][num]) continue; 34 v[x][num]=1; 35 for(int i=head[x];i;i=e[i].nex) 36 { 37 j=e[i].y; 38 if(d[x][num]+e[i].w<d[j][num]) 39 { 40 d[j][num]=d[x][num]+e[i].w; 41 q.push(make_pair(d[j][num],j+n*num)); 42 } 43 if(num==k) continue; 44 if(d[j][num+1]>d[x][num]) 45 { 46 d[j][num+1]=d[x][num]; 47 q.push(make_pair(d[j][num+1],j+(num+1)*n)); 48 } 49 } 50 } 51 } 52 int main() 53 { 54 int tmp,x,y,z; 55 cin>>n>>tmp>>s>>t>>k; 56 while(tmp--) 57 { 58 cin>>x>>y>>z; 59 add(x,y,z);add(y,x,z); 60 } 61 DJ(); 62 return 0; 63 }
当然我们也不一定是k条路免费,可能是k条路可以打折【冻结】。
这个时候需要注意一点,因为不是免费,所以我们不一定会全数使用k次机会。
举个栗子:原本只需要三步的最短路,使用四次就会多走一条路,这条路是若是免费当然没有影响,但如果有权值则不行。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include<iostream> #include<cstring> #include<queue> #define ll long long #define inf 0x3f3f3f3f using namespace std; typedef pair<int,int> pir; priority_queue<pir,vector<pir>,greater<pir> > q; struct node { int nex,y,w; }e[2002]; int m,n,s,t,k; int head[1010]; int d[1010][55]; bool v[1010][55]; void add(int x,int y,int z) { e[++m].y=y; e[m].w=z; e[m].nex=head[x]; head[x]=m; } void DJ() { memset(d,0x3f,sizeof(d)); int x,j,num; d[s][0]=0; q.push(make_pair(0,s)); while(q.size()) { x=q.top().second;q.pop(); num=x/n;x%=n; if(v[x][num]) continue; v[x][num]=1; for(int i=head[x];i;i=e[i].nex) { j=e[i].y; if(d[x][num]+e[i].w<d[j][num]) { d[j][num]=d[x][num]+e[i].w; q.push(make_pair(d[j][num],j+n*num)); } if(num==k) continue; if(d[j][num+1]>d[x][num]+e[i].w/2) { d[j][num+1]=d[x][num]+e[i].w/2; q.push(make_pair(d[j][num+1],j+(num+1)*n)); } } } } int main() { int tmp,x,y,z; cin>>n>>tmp>>k; s=1;t=n; while(tmp--) { cin>>x>>y>>z; add(x,y,z);add(y,x,z); } DJ(); int ans=inf; for(int i=0;i<=k;i++) ans=min(ans,d[t][i]); cout<<ans<<endl; return 0; }