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]了;

所以我们可以直接把边当成点,对边做最短路(用堆优化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\n",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\n",ans);
    }
}

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

原文地址:https://www.cnblogs.com/dilthey/p/9016699.html

时间: 2024-10-01 00:37:52

CSU 1808 - 地铁 - [最短路变形]的相关文章

【最短路】【STL】CSU 1808 地铁 (2016湖南省第十二届大学生计算机程序设计竞赛)

题目链接: http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1808 题目大意: N个点M条无向边(N,M<=105),每条边属于某一条地铁Ci(Ci<=109),每条边有一个耗时,如果乘Ci号线地铁到达一个节点换乘Cj号线地铁离开,还需要花费|Ci-Cj|时间. 求1到n的最小花费时间. 题目思路: [最短路][STL] d[u][Ci]表示从1到u,最后一条地铁是Ci号线的最小耗时.按照边做,每条边枚举上一个是从哪一条地铁坐过来的,更新答案

CSU 1808 地铁

湖南省第十二届大学生计算机程序设计竞赛$F$题. 最短路. 如果只记录到某个节点的最短路,显然是错误的.这题的状态有两个量决定,即到了哪一个节点,最后一辆乘坐的是几号线.这个可以用$map$记录一下. 要注意的是:如果用$SPFA$,因为要标记某个状态是否在队列中,还需要额外开一个$map$,这样可能导致超时:用$dijkstra$$+$优先队列优化的话就可以通过. #pragma comment(linker, "/STACK:1024000000,1024000000") #inc

1808: 地铁

1808: 地铁 Time Limit: 5 Sec  Memory Limit: 128 MBSubmit: 693  Solved: 161[Submit][Status][Web Board] Description Bobo 居住在大城市 ICPCCamp. ICPCCamp 有 n 个地铁站,用 1,2,…,n 编号. m 段双向的地铁线路连接 n 个地铁站,其中第 i 段地铁属于 ci 号线,位于站 ai,bi 之间,往返均需要花费 ti 分钟(即从 ai 到 bi 需要 ti 分钟

URAL 1934 Black Spot --- 简单最短路变形

边权为1,在维护最短路的同时维护p值最小,我直接存的(1-p),即不遇见的概率,要使得这个值最大. #include <iostream> #include <cstdlib> #include <cstring> #include <string> #include <cstdio> #include <cmath> #include <algorithm> #include <vector> #includ

UESTC 915 方老师的分身II --最短路变形

即求从起点到终点至少走K条路的最短路径. 用两个变量来维护一个点的dis,u和e,u为当前点的编号,e为已经走过多少条边,w[u][e]表示到当前点,走过e条边的最短路径长度,因为是至少K条边,所以大于K条边的当做K条边来处理就好了.求最短路的三个算法都可以做,我这里用的是SPFA,比较简洁. 代码: #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #incl

zoj 1655 Transport Goods (最短路变形)

Transport Goods Time Limit: 2 Seconds      Memory Limit: 65536 KB The HERO country is attacked by other country. The intruder is attacking the capital so other cities must send supports to the capital. There are some roads between the cities and the

zoj1655 最短路变形

题意:HERO过的首都需要货物,需要从其他的城市吧货物送到首都,每条道路都会需要消耗一定比例的货物,问最多能送多少货物到首都. 思路:如果每个点的比例是1,到达首都的比例就是经过的路径的(1-消耗比)的乘积,反正是无向的,所以可以反过来推,首都的货物比是1,而到达每座 城市的货物就是所经过的路径(1-消耗比)的乘积,则由此可见,我们可以求首都到任意城市的最大比值:最后把每个点的最大比值乘以每个点的货物加起来 即是结果. #include<stdio.h> #include<string.

HN0I2000最优乘车 (最短路变形)

HN0I2000最优乘车 (最短路变形) [试题]为了简化城市公共汽车收费系统,某城市决定对大部分的公共汽车都采用一票制,但由于某些公共汽车所经过的停车站太多和路途太长,就采用两票或多票制.经过这种票制改革后,人们坐公共汽车从一个站到另一个站时,就不得不选择一个好的乘车方案,以使他们的乘车费用最低. 为了方便于求出最佳的乘车方案,我们假设: l  采用一票制的公共汽车,无论从哪个站上车到那个站下车,乘该公共汽车的费用为1(费用单位). l  采用多票制的公共汽车,将设立某些站为关键站:那么,如果

POJ 1797 Heavy Transportation (最短路变形)

Heavy Transportation Time Limit: 3000MS   Memory Limit: 30000K Total Submissions: 20364   Accepted: 5401 Description Background Hugo Heavy is happy. After the breakdown of the Cargolifter project he can now expand business. But he needs a clever man