zoukankan      html  css  js  c++  java
  • 分层图

    BZOJ 飞行路线:传送门

    分层图的思想可以解决这样的问题:有n次免费的机会下的最短路问题,例如飞行路线。

    题意就是一个无向图,两点之间有费用。而你有k次免费搭乘飞机的机会。这种情况下问从a点到b点的最少消费。

    这种问题是不能直接用最短路解决的。可以用DP的思想,dis[n][k]数组为到n这个点用了k次优惠的最少消费。这里就不展开。

    我们现在介绍一种新思路。

    我们可以构造k+1张该无向图,那么第i张图和第i+1张图如何连接呢,就是用已知的边把边权变为0连在两张图的端点上。

    比如已知一条边(u,v,w),我们建图的时候就可以添加这样一条边(i*n+u,(i+1)*n+v,0)。

    然后我们就有了一张有n*(k+1)个点的无向图,再直接用dijkstra就可以了。

    来看代码

    #include<stdio.h>
    #include<queue>
    #include<iostream>
    #define N 200010
    #define WQD 2000000001
    using namespace std;
    int num=0,m,n,k,s,t,head[N],dis[N];
    
    struct EDGE
    {
        int w,to,next;
    }e[20*N];
    
    void add(int f,int t,int w)
    {
        e[++num].next=head[f];
        e[num].w=w;
        e[num].to=t;
        head[f]=num;
    }
    struct VD
    {
        int v,dis;
        bool operator < (const VD &a)const
        {
            return a.dis<dis;
        }
    }; 
    void dijkstra(int st)
    {
        priority_queue <VD> q;
        for(int i=0;i<(k+1)*n;i++) dis[i]=WQD;
        dis[st]=0;
        VD temp;
        temp.v=st;temp.dis=0;
        q.push(temp);
        while(q.size())
        {
            temp=q.top();
            q.pop();
            int p=temp.v;
            if(dis[p]<temp.dis) continue;
            for(int i=head[p];i;i=e[i].next)
            {
                if(dis[e[i].to]>dis[p]+e[i].w)
                {
                    dis[e[i].to]=dis[p]+e[i].w;
                    temp.v=e[i].to;temp.dis=dis[e[i].to];
                    q.push(temp);
                }
            }
            
        }
    }
    int main()
    {
        scanf("%d%d%d",&n,&m,&k);
        scanf("%d%d",&s,&t);
        for(int i=1;i<=m;i++)
        {
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            for(int j=0;j<=k;j++)    //建k+1张图;
            {
                add(j*n+a,j*n+b,c);
                add(j*n+b,j*n+a,c);
            }
            for(int j=0;j<k;j++)    //建边权为0的边连接两张相邻的图;
            {
                add(j*n+a,(j+1)*n+b,0);
                add(j*n+b,(j+1)*n+a,0);
            }
        }
        dijkstra(s);
        printf("%d",dis[k*n+t]);
        return 0;
     } 

    这样的操作让这种题目就变成了直接的最短路问题。

    不过需要注意的是空间范围,因为我们要建立一个有n*(k+1),个点的无向图,会很大。所以一定要注意范围,不然会RE;

  • 相关阅读:
    iBatis查询时报“列名无效”无列名的错误原因及解决方法
    【转】Spring结合Quartz实现多任务定时调用
    关于jar中读取包内和包外文件
    【摘自百度文库】数据库水平切分的实现原理解析
    web.xml 中的listener、 filter、servlet 加载顺序及其详解(转载)
    EL表达式
    【转】使用XFire+Spring构建Web Service
    慎用href="javascript:void(0)"
    POI导出EXCEL【摘自:oschina.net】
    【转】IBM websphere6.1 不支持泛型、intInteger类型的自动装箱和拆箱问题
  • 原文地址:https://www.cnblogs.com/xcsj/p/12264415.html
Copyright © 2011-2022 走看看