zoukankan      html  css  js  c++  java
  • [JLOI2011]飞行路线

    题目描述

    Alice 和Bob现在要乘飞机旅行,他们选择了一家相对便宜的航空公司。该航空公司一共在n个城市设有业务,设这些城市分别标记为0到n-1,一共有m种航线,每 种航线连接两个城市,并且航线有一定的价格。Alice和Bob现在要从一个城市沿着航线到达另一个城市,途中可以进行转机。航空公司对他们这次旅行也推 出优惠,他们可以免费在最多k种航线上搭乘飞机。那么Alice和Bob这次出行最少花费多少?

    输入格式

    数据的第一行有三个整数,n,m,k,分别表示城市数,航线数和免费乘坐次数。

    第二行有两个整数,s,t,分别表示他们出行的起点城市编号和终点城市编号。(0<=s,t<n)

    接下来有m行,每行三个整数,a,b,c,表示存在一种航线,能从城市a到达城市b,或从城市b到达城市a,价格为c。(0<=a,b<n,a与b不相等,0<=c<=1000)

    2<=n<=10000,1<=m<=50000,0<=k<=10.

    输出格式

    只有一行,包含一个整数,为最少花费。


    首先明确一个概念,最短路实际上是一种动态规划。因为v的最短路由v之前的点u的最短路加上它们之间的边长更新而来。

    而这题就好像给动态规划加了一层状态:免费乘坐次数。

    解法1:我们可以直接沿袭动规的做法,直接给状态加一维:dis(i,j)表示免费乘坐了j次航线之后,i的最短路长度。设i的前驱节点集合为pre(u),那么:

    [dis[i][j]=Min_{k{in}pre(i)}{{}Min(dis[k][j]+edge(k,i),dis[k][j-1]){}} ]

    解法2:分层图最短路。把原图建成k层,每层都等于原图。若原图中有edge(u,v),那么建图时把每一层的u都向下一层的v连一条有向边,长度为0。最后答案是所有层终点的最短路的最小值。

    两个解法的时间复杂度都为:O((N+M)log(K*(N+M)))。给出分层图最短路的代码:

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<queue>
    #define maxn 10001
    #define maxm 50001
    #define maxk 11
    using namespace std;
     
    struct edge{
        int to,dis,next;
        edge(){}
        edge(const int &_to,const int &_dis,const int &_next){ to=_to,dis=_dis,next=_next; }
    }e[maxm*maxk*4];
    int head[maxn*maxk],k;
     
    int dis[maxn*maxk];
    bool vis[maxn*maxk];
    int n,m,q,s,t;
     
    inline int read(){
        register int x(0),f(1); register char c(getchar());
        while(c<'0'||'9'<c){ if(c=='-') f=-1; c=getchar(); }
        while('0'<=c&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
        return x*f;
    }
    inline void add(const int &u,const int &v,const int &w){ e[k]=edge(v,w,head[u]),head[u]=k++; }
     
    inline void dijkstra(){
        priority_queue< pair<int,int>,vector< pair<int,int> >,greater< pair<int,int> > > q;
        memset(dis,0x3f,sizeof dis),dis[s]=0;
        q.push(make_pair(0,s));
        while(q.size()){
            int u=q.top().second; q.pop();
            if(vis[u]) continue; vis[u]=true;
            for(register int i=head[u];~i;i=e[i].next){
                int v=e[i].to;
                if(dis[v]>dis[u]+e[i].dis) dis[v]=dis[u]+e[i].dis,q.push(make_pair(dis[v],v));
            }
        }
    }
     
    int main(){
        memset(head,-1,sizeof head);
        n=read(),m=read(),q=read(),s=read()+1,t=read()+1;
        for(register int i=1;i<=m;i++){
            int u=read()+1,v=read()+1,w=read();
            for(register int j=0;j<=q;j++) add(u+n*j,v+n*j,w),add(v+n*j,u+n*j,w);
            for(register int j=1;j<=q;j++) add(u+n*(j-1),v+n*j,0),add(v+n*(j-1),u+n*j,0);
        }
        dijkstra();
     
        int ans=0x3f3f3f3f;
        for(register int i=0;i<=q;i++) ans=min(ans,dis[t+n*i]);
        printf("%d
    ",ans);
        return 0;
    }
    
  • 相关阅读:
    【一些思路】web和app测试的区别
    【Python】I/O和比赛的其他一些问题
    【Python】迭代器和生成器的个人理解,再讲一讲协程
    【TCP/IP】如果打不开一个网页,需要如何处理?
    DOM事件
    GASP动画的基本使用
    Velocity的使用方法
    Swiper和Swiper Animate使用方法
    DOM操作
    JavaScript函数
  • 原文地址:https://www.cnblogs.com/akura/p/10975872.html
Copyright © 2011-2022 走看看