分层图最短路问题

分层图最短路是指在可以进行分层图的图上解决最短路问题。
 
一般模型是:
 
在图上,有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);
}

当然也完全可以用一个二维数组来存,方便好写,代码如下:

 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 }
View Code

 当然我们也不一定是k条路免费,可能是k条路可以打折【冻结】。

这个时候需要注意一点,因为不是免费,所以我们不一定会全数使用k次机会。

举个栗子:原本只需要三步的最短路,使用四次就会多走一条路,这条路是若是免费当然没有影响,但如果有权值则不行。

#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;
}
View Code

 

转载于:https://www.cnblogs.com/g-xf/p/11258388.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值