zoukankan      html  css  js  c++  java
  • [JLOI2011]飞行路线 分层图最短路


    题目描述:

    Alice和Bob现在要乘飞机旅行,他们选择了一家相对便宜的航空公司。该航空公司一共在nn个城市设有业务,设这些城市分别标记为0到n-1,一共有m种航线,每种航线连接两个城市,并且航线有一定的价格

    Alice和Bob现在要从一个城市沿着航线到达另一个城市,途中可以进行转机。航空公司对他们这次旅行也推出优惠,他们可以免费在最多k种航线上搭乘飞机。那么Alice和Bob这次出行最少花费多少?


    题解:


    说实话还是一道比较明显的分层图最短路。
    其实也可以不按分层图做,直接暴力开一个二维距离 $d[i][j]$,代表第 $i$ 个节点,用过 $k$ 次免费路线即可。
    不过这样的话好像有些麻烦,而且代码不太好写。

    讲一下正解: 分层图最短路。
    我们观察到 $k$ 很小,我们就从 $k$ 入手分析。
    对于每一个 $k$ ,我们都建立一个由源点到汇点的有向图,而特别地,层与层之间都有一些边权为0 的边,代表免费走的边。
    由于这些免费走的边都是由第 $i$ 层图单向连到第 $i+1$ 层图的,我们就不必担心多走免费路线。

    Code:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    #include<vector>
    #include<queue>
    #include<string>
    const int maxn=3000000;
    using namespace std;
    
    void setIO(string a){
    	freopen((a+".in").c_str(),"r",stdin);
    }
    int s,t,cnt;
    int head[maxn], to[maxn], nex[maxn], val[maxn];
    void add_edge(int u,int v,int c){
    	nex[++cnt]=head[u],head[u]=cnt,to[cnt]=v,val[cnt]=c;
    }
    int d[maxn];
    int inq[maxn];
    deque<int>Q;
    void spfa()
    {
        memset(d,0x3f,sizeof(d));
        d[s]=0,inq[s]=1;Q.push_back(s);
        while(!Q.empty())
        {
            int u=Q.front();Q.pop_front();inq[u]=0;
            for(int v=head[u];v;v=nex[v])
                if(d[to[v]]>d[u]+val[v])
                {
                    d[to[v]]=d[u]+val[v];
                    if(!inq[to[v]])
                    {
                        inq[to[v]]=1;
                        if(Q.empty()||d[Q.front()]>=d[to[v]])Q.push_front(to[v]);
                        else Q.push_back(to[v]);
                    }
                }
        }
    }
    int main(){
    	//setIO("input");
    	int n,m,k;
    	scanf("%d%d%d%d%d",&n,&m,&k,&s,&t);
    	 for(int i=1;i<=m;i++)
        {
        	int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            add_edge(a,b,c);
            add_edge(b,a,c);
            for(int j=1;j<=k;j++)
            {
                add_edge(a+(j-1)*n,b+j*n,0);
                add_edge(b+(j-1)*n,a+j*n,0);
                add_edge(a+j*n,b+j*n,c);
                add_edge(b+j*n,a+j*n,c);
            }
        }
    	spfa();
    	printf("%d
    ",d[t+n*k]);
    	return 0;
    }
    

      

  • 相关阅读:
    出错处理函数abort、exit、atexit、strerror. . .
    linux查询系统信息命令
    [转载]比google和百度强十倍的搜索类网站
    陶  朱  商  经
    ip的划分,超详细.【网管常识】
    linux的hostname修改详解
    勤于寻找谈话资料
    Windows常用命令集
    C语言中printf格式
    How to disable SELinux
  • 原文地址:https://www.cnblogs.com/guangheli/p/9888211.html
Copyright © 2011-2022 走看看