分层最短路

作者: 雨落八千里 | 来源:发表于2019-07-31 22:14 被阅读7次

分层图最短路是指在可以进行分层图的图上解决最短路问题。分层图:可以理解为有多个平行的图。
图片来源

这个图的意思是第0层是原始的图,上面的1—k层都是第0层的映射。

  • 层内(同一层),仍然是u->v的关系,权值为w.
  • 层间(不同层),也是u->v的关系,但权值是0,
  • 比如图中的S_0a_0是同一层距离为3,S_0a_1是不同层距离为0。这就是分层操作。
    所以开数组的时候要格外注意,以为有k+1层,那么就n*(k+1)个点,那么就有(2k+1)*m条边。

飞行路线

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
const int M=5000500;
int head[M],cnt;
struct node
{
    int v,w;
    int nxt;
}edge[M];
int n,m,k,s,t,x,y,w;
int dis[M],vis[M];
void add(int x,int y,int w)
{
    edge[++cnt].nxt=head[x];
    edge[cnt].v=y;
    edge[cnt].w=w;
    head[x]=cnt;
}
void Dijkstra(int x)
{
    memset(vis,0,sizeof(vis));
    memset(dis,INF,sizeof(dis));
    //vis[x]=1;
    dis[x]=0;
    priority_queue<pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > > qu;//first是dis[v]的最小距离,second是当前点的id,优先队列的优先级先考虑pair.first
    qu.push(make_pair(0,x));
    while(!qu.empty( ))
    {
        int u=qu.top( ).second;
        qu.pop( );
        if(!vis[u])
        {
            vis[u]=1;
            for(int i=head[u];i!=-1;i=edge[i].nxt)
            {
                int v=edge[i].v;
                if(dis[v]>dis[u]+edge[i].w)
                {
                    dis[v]=dis[u]+edge[i].w;
                    qu.push(make_pair(dis[v],v));
                }
            }

        }

    }
}
int main( )
{
    cin>>n>>m>>k>>s>>t;
    s++,t++;
    cnt=0;
    memset(head,-1,sizeof(head));
    for(int i=1;i<=m;i++)
    {
        cin>>x>>y>>w;
        x++,y++;
        for(int j=0;j<=k;j++)
        {
            add(x+j*n,y+j*n,w);//相同层,距离为w
            add(y+j*n,x+j*n,w);
        }
        for(int j=1;j<=k;j++)
        {
            add(x+n*(j-1),y+n*j,0);//上下层边,距离为0
            add(y+n*(j-1),x+n*j,0);
        }
    }
    for(int i=1;i<=k;i++)
    {
        add(t+(i-1)*n,t+i*n,0);//连接各层的t
    }
    Dijkstra(s);
    cout<<dis[t+k*n]<<endl;//输出最高层的t就是答案
    return 0;
}

dp思想

想象将一个点拆分为k + 1个点,分别表示到这个点时,免费权消耗了0次,1次,2次......k次
这样实际我们可以把这k个点想象成对应dp的不同的状态

  • dis[i][j]表示到第i个点时,消耗了j次乘车权后的最短路线
  • vis[ i ][ j ] 代表到达 i 用了 j 次免费机会的情况是否出现过.

我们用to表示要到达的点,x表示父亲节点,就有

dis[to][j] = min(dis[x][j] + val(x, to), dis[x][j - 1])
因为我们跑最短路时是从前向后跑,也就是当前状态推出后继状态,所以实际上我们可以推出两个可能状态
如果我们消耗了免费过路权(前提是还有免费的过路权)
dis[to][j] = min{dis[x][j - 1]}
如果我们没消耗免费过路权
dis[to][j] = min{dis[x][j] + val(x, to)}

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
const int M=1e5+10;
int dis[M][15];
int vis[M][15];
int head[M],cnt;
int n,m,k,s,t;
struct node
{
    int v;
    int w;
    int nxt;
} edge[M<<4];
void add(int x,int y,int w)
{
    edge[++cnt].nxt=head[x];
    edge[cnt].v=y;
    edge[cnt].w=w;
    head[x]=cnt;
}
void Dijkstra(int x)
{
    memset(vis,0,sizeof(vis));
    memset(dis,INF,sizeof(dis));
    dis[x][0]=0;
    priority_queue<pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > > qu;
    qu.push(make_pair(0,x));
    while(!qu.empty( ))
    {
        int u=qu.top( ).second;
        qu.pop( );
        int tt=u/n;//求出已经使用了多少次免费的路权,相当于分层思想中处在多少层
        u%=n;//当前的节点
        if(vis[u][tt]==1)
        {
            continue;
        }
        vis[u][tt]=1;
        for(int i=head[u]; i!=-1; i=edge[i].nxt)
        {
            int v=edge[i].v;
            if(!vis[v][tt]&&dis[v][tt]>dis[u][tt]+edge[i].w)
            {
                dis[v][tt]=dis[u][tt]+edge[i].w;
                qu.push(make_pair(dis[v][tt],v+tt*n));//v+tt*n相当于分层思想中的同一层,于是要加边长w
            }
        }
        if(tt<k)
        {
            for(int i=head[u]; i!=-1; i=edge[i].nxt)
            {
                int v=edge[i].v;
                if(!vis[v][tt+1]&&dis[v][tt+1]>dis[u][tt])
                {
                    dis[v][tt+1]=dis[u][tt];
                    qu.push(make_pair(dis[v][tt+1],(tt+1)*n+v));//v+(tt+1)*n相当于分层中的不同层,边长w=0
                }
            }
        }
    }

}
int main( )
{
    cin>>n>>m>>k>>s>>t;
    cnt=0;
    int x,y,w;
    memset(head,-1,sizeof(head));
    for(int i=0; i<m; i++)
    {
        cin>>x>>y>>w;
        add(x,y,w);
        add(y,x,w);
    }
    Dijkstra(s);
    int ans=INF;
    for(int i=0; i<=k; i++)
    {
        ans=min(ans,dis[t][i]);
    }
    cout<<ans<<endl;
    return 0;

}

相关文章

  • 分层最短路

    分层图最短路是指在可以进行分层图的图上解决最短路问题。分层图:可以理解为有多个平行的图。图片来源这个图的意思是第0...

  • Magical Girl Haze(分层最短路)

    Magical Girl Haze注意这个是单向的,搞了半天,没看懂英文

  • 电力四种短路

    电力短路大如天,一旦发生破命钱 单相短路概率高,心中时刻设防线 三相短路最严重,预防发生常挂念 两相短路常发生,偶...

  • 用户分层基础方法:RFM分层实践

    一、前言 如果没有做分层基本就没有在做运营这件事。——王慧文 分层是用户运营最基础的底层思维。为什么要做分层?简单...

  • pulsar 以Segment为中心的架构

    Pulsar的分层架构 Apache Pulsar和其他消息系统最根本的不同是采用分层架构。 Apache Pul...

  • Floyd-Warshshall(未简化&数组版)

    解决多元最短路径问题(每两点之间的最短路):一次最外层循环表示借助一条边 初始化:d[i][i] = 0; 其他为...

  • 实战!通过一个简单的java计算器说明分层思想!

    分层思想概述 代码若要达到:易维护、可复用、可扩展、够灵活、低耦合等特点;编程人员必须建立起分层思想。 最简单的是...

  • 设计中的短路电流的校核

    短路电电流 一)为什么计算最大短路电流?为什么计算最小短路电流? 目的:测试对于短路计算意义的理解 答案:计算最大...

  • 用户分层,主抓20%优质客户

    1、今天最触动我的一个点:用户分层,20%的客户,产生80%的利润。 2、对你实现目标有什么启发? 用户分层管理,...

  • 遍历 最短路径 1.单源最短路 有权图-Dijkstra 多源头最短路-Floyd算法 —————————————...

网友评论

    本文标题:分层最短路

    本文链接:https://www.haomeiwen.com/subject/sxzorctx.html