zoukankan      html  css  js  c++  java
  • CSU 1808

    题目链接:http://acm.csu.edu.cn/csuoj/problemset/problem?pid=1808

    Time limit: 5000 ms Memory limit: 131072 kB

    Bobo 居住在大城市 ICPCCamp。

    ICPCCamp 有 n 个地铁站,用 1,2,…,n 编号。 m 段双向的地铁线路连接 n 个地铁站,其中第 i 段地铁属于 c i 号线,位于站 a i,b i 之间,往返均需要花费 t i 分钟(即从 a i 到 b i需要 t i 分钟,从 b i 到 a i 也需要 t i 分钟)。
    众所周知,换乘线路很麻烦。如果乘坐第 i 段地铁来到地铁站 s,又乘坐第 j 段地铁离开地铁站 s,那么需要额外花费 |c i-c j | 分钟。注意,换乘只能在地铁站内进行。
    Bobo 想知道从地铁站 1 到地铁站 n 所需要花费的最小时间。

    Input

    输入包含不超过 20 组数据。
    每组数据的第一行包含两个整数 n,m (2≤n≤10 5,1≤m≤10 5).
    接下来 m 行的第 i 行包含四个整数 a i,b i,c i,t i (1≤a i,b i,c i≤n,1≤t i≤10 9).
    保证存在从地铁站 1 到 n 的地铁线路(不一定直达)。

    Output

    对于每组数据,输出一个整数表示要求的值。

    Sample Input

    3 3
    1 2 1 1
    2 3 2 1
    1 3 1 1
    3 3
    1 2 1 1
    2 3 2 1
    1 3 1 10
    3 2
    1 2 1 1
    2 3 1 1
    

    Sample Output

    1
    3
    2

    题解:

    如果只记录到某个节点x的最短路长度d[x],并且记录对应于d[x],是坐哪号线来到节点x的,这样显然是错误的。

    原因比如这样的样例:

    3 3
    1 2 1 2
    1 2 3 3
    2 3 3 5

    可以看出,d[x]要扩展到d[x][c],即这题的状态有两个量决定:到了节点x,最后乘坐的是c号线;

    那么,如果我们把节点x用若干条边Edge(u1→x)…Edge(uk→x)来代替,那么我们就相当于把d[x]要扩展到d[x][c]了;

    所以我们可以直接把边当成点,对边做最短路。

    (这题对边做最短路,如果用spfa的话会TLE,要使用堆优化dijkstra)

    AC代码:

    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<iostream>
    #include<vector>
    #include<algorithm>
    #include<queue>
    using namespace std;
    typedef long long LL;
    typedef pair<LL,int> Pair;
    
    const LL INF=1e18;
    const int maxn=1e5+10;
    const int maxm=2e5+10; //无向边拆成两条有向边
    
    int n,m;
    
    struct Edge{
        int u,v,c;
        int next;
        LL t;
    };
    Edge E[maxm];
    int head[maxn],ne;
    void init()
    {
        ne=0;
        memset(head,-1,sizeof(head));
    }
    void addedge(int u,int v,int c,LL t)
    {
        E[ne].u=u, E[ne].v=v, E[ne].c=c, E[ne].t=t;
        E[ne].next=head[u];
        head[u]=ne++;
    }
    
    LL ans;
    LL d[maxm];
    bool vis[maxm];
    void dijkstra(int st)
    {
        priority_queue< Pair, vector<Pair>, greater<Pair> > Q;
    
        memset(vis,0,sizeof(vis));
        for(int i=0;i<ne;i++) d[i]=INF;
        ans=INF;
    
        for(int i=head[st];i!=-1;i=E[i].next)
        {
            d[i]=E[i].t;
            Q.push(Pair(d[i],i));
        }
        while(!Q.empty())
        {
            int x=Q.top().second; Q.pop();
    
            if(vis[x]) continue;
            vis[x]=1;
            if(E[x].v==n) ans=min(ans,d[x]);
    
            for(int y=head[E[x].v];y!=-1;y=E[y].next)
            {
                if(vis[y]) continue;
                if(d[y]>d[x]+E[y].t+abs(E[y].c-E[x].c))
                {
                    d[y]=d[x]+E[y].t+abs(E[y].c-E[x].c);
                    Q.push(Pair(d[y],y));
                }
            }
        }
    }
    int main()
    {
        while(scanf("%d%d",&n,&m)!=EOF)
        {
            init();
            for(int i=1;i<=m;i++)
            {
                int u,v,c; LL t;
                scanf("%d%d%d%lld",&u,&v,&c,&t);
                addedge(u,v,c,t);
                addedge(v,u,c,t);
            }
    
            dijkstra(1);
            printf("%lld
    ",ans);
        }
    }
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<iostream>
    #include<vector>
    #include<algorithm>
    #include<queue>
    using namespace std;
    typedef long long LL;
    typedef pair<LL,int> Pair;
    
    const LL INF=1e18;
    const int maxn=1e5+10;
    const int maxm=2e5+10; //无向边拆成两条有向边
    
    int n,m;
    
    struct Edge{
        int u,v,c;
        LL t;
    };
    vector<Edge> E;
    vector<int> G[maxn];
    void init(int l,int r)
    {
        E.clear();
        for(int i=l;i<=r;i++) G[i].clear();
    }
    void addedge(int u,int v,int c,LL t)
    {
        E.push_back((Edge){u,v,c,t});
        G[u].push_back(E.size()-1);
    }
    
    LL ans;
    LL d[maxm];
    bool vis[maxm];
    void dijkstra(int st)
    {
        priority_queue< Pair, vector<Pair>, greater<Pair> > Q;
    
        memset(vis,0,sizeof(vis));
        for(int i=0;i<E.size();i++) d[i]=INF;
        ans=INF;
    
        for(int i=0;i<G[st].size();i++)
        {
            int x=G[st][i];
            d[x]=E[x].t;
            Q.push(Pair(d[x],x));
        }
        while(!Q.empty())
        {
            int x=Q.top().second; Q.pop();
    
            if(vis[x]) continue;
            vis[x]=1;
            if(E[x].v==n) ans=min(ans,d[x]);
    
            for(int i=0;i<G[E[x].v].size();i++)
            {
                int y=G[E[x].v][i];
                if(vis[y]) continue;
                if(d[y]>d[x]+E[y].t+abs(E[y].c-E[x].c))
                {
                    d[y]=d[x]+E[y].t+abs(E[y].c-E[x].c);
                    Q.push(Pair(d[y],y));
                }
            }
        }
    }
    int main()
    {
        while(scanf("%d%d",&n,&m)!=EOF)
        {
            init(1,n);
            for(int i=1;i<=m;i++)
            {
                int u,v,c; LL t;
                scanf("%d%d%d%lld",&u,&v,&c,&t);
                addedge(u,v,c,t);
                addedge(v,u,c,t);
            }
    
            dijkstra(1);
            printf("%lld
    ",ans);
        }
    }

    注:两份代码的区别是分别用链式前向星和vector邻接表存图。

  • 相关阅读:
    Angular5的new feature
    Angular集成UEditor
    Angular集成admin-lte框架
    Angular TypeScript开发环境集成jQuery扩展插件
    如何在 Docker 容器中运行 Kali Linux 2.0
    信息系统安全等级保护基本要求
    Angular学习笔记
    Ubuntu16.04部署phantomjs的一个问题
    仿探探卡片滑动vue封装并发布到npm
    使用vscode,新建.vue文件,tab自动生成vue代码模板
  • 原文地址:https://www.cnblogs.com/dilthey/p/9016699.html
Copyright © 2011-2022 走看看