• [Luogu P4568][JLOI 2011]飞行路线


    这题显然一看就是要跑最短路的嘛233333

    但是这题有个关键限制条件,就是

    可以免费在最多k种航线上搭乘飞机

    因此我们不能直接建图,需要考虑一些特殊的建图方法。没错,就决定是你了,分层图。

    注意到k<=10,于是我们考虑把u点拆分,把到u点时用过的免费次数加入其中。也就是如果用i表示这一个点用过的免费次数,则加边(u,v)时,还要加上(u + i * n,v + (i + 1) * n),边权为0,即我在u到v时使用了一次免费次数。这样我们就可以构建出一个含有多层的图。然后愉快的跑dijkstra就行。

    统计答案的时候,我们对dis[t + i * n]进行取最小值,也就是对所有用i次免费到达t的费用取一个最小值就是最终答案了。

    这题唯一的难点就是建图的过程,只要掌握好建分层图的方法,然后就可以直接上板子了。复杂度O(kmlogn),可以通过。

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #include<algorithm>
    #define N 1000010
    #define M 5000010
    using namespace std;
    int head[N],nxt[M],to[M],val[M];
    int n,m,cnt;
    void Add(int u,int v,int w)
    {
        nxt[++cnt] = head[u];
        head[u] = cnt;
        to[cnt] = v;
        val[cnt] = w;
        return;
    }
    int k,s,t;
    int dis[N];
    struct qwq
    {
        int u,dis;
        bool operator < (const qwq &a) const
        {
            return dis > a.dis;
        }
    }top,node;
    priority_queue<qwq>q;
    const int inf = 100000010;
    bool vis[N];
    void dijkstra()
    {
        for(int i = 0;i <= n + k * n;i++) dis[i] = inf;
        dis[s] = 0;
        top.u = s;
        top.dis = 0;
        q.push(top);
        while(q.size())
        {
            top = q.top();
            q.pop();
            int u = top.u;
            if(!vis[u])
            {
                vis[u] = 1;
                for(int i = head[u];i;i = nxt[i])
                {
                    int v = to[i];
                    if(dis[v] > dis[u] + val[i])
                    {
                        dis[v] = dis[u] + val[i];
                        node.u = v,node.dis = dis[v];
                        q.push(node);
                    }
                }
            }
        }
        return;
    }
    int main()
    {
        scanf("%d %d %d",&n,&m,&k);
        scanf("%d %d",&s,&t);
        for(int j = 1;j <= m;j++)
        {
            int u,v,w;
            scanf("%d %d %d",&u,&v,&w);
            Add(u,v,w);
            Add(v,u,w);
            for(int i = 1;i <= k;i++)
            {
                Add(u + (i - 1) * n,v + i * n,0);
                Add(v + i * n,u + i * n,w);
                Add(v + (i - 1) * n,u + i * n,0);
                Add(u + i * n,v + i * n,w);
            }
        }
        dijkstra();
        int ans = inf;
        for(int i = 0;i <= k;i++) ans = min(dis[t + i * n],ans);
        printf("%d",ans);
        return 0;
    }
  • 相关阅读:
    sync_with_stdio(false)和cin.tie(NULL)
    会场安排问题(贪心 两种方法)
    面向对象分析和设计笔记——第6章界面组件
    用Java实现文件复制
    面向对象分析和设计笔记——第5章输入输出
    面向对象分析和设计笔记——第4章设计模式
    常规类、抽象类和接口的对比分析
    使用for-each循环的三种情况
    StringTokenizer类
    String类的常用方法
  • 原文地址:https://www.cnblogs.com/lijilai-oi/p/10901973.html
Copyright © 2020-2023  润新知