C - 地铁 CSU - 1808

 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

狄杰斯特拉变形 按边去访问,求出经过每一条边的最短路。这个题如果按点的话,到达n点的不一定是最优解,因为这是在之前某个点最短路更新的,在有些情况下前面不走最短有可能解更优。所以应该走遍所有情况,直接暴力肯定不行,就用狄杰斯特拉按边访问能解决。

vector存图

#include <bits/stdc++.h>

#define ll long long

const ll inf =1e16;

using namespace std;
ll n,m,top;
struct code
{
    ll to,id,v,edg;
} temp,edge[200005];
int tts;
vector<code>p[200005];
ll dist[200005];
pair<ll,ll>tep;
pair<ll,ll>tt;
void dijst()
{
    priority_queue< pair<ll,ll>, vector<pair<ll,ll> >, greater< pair<ll, ll> > > q;
    for(int i=0; i<top; i++)
        dist[i]=inf;
    tts=p[1].size();
    for(int i=0; i<tts; i++)
    {
        if(dist[p[1][i].edg]>p[1][i].v)
        {
            dist[p[1][i].edg]=p[1][i].v;
            tep.first=p[1][i].v;
            tep.second=p[1][i].edg;
            q.push(tep);
        }
    }
    ll ans=inf;
    while(!q.empty())
    {
        tt=q.top();
        q.pop();
        ll u=tt.second;
        int nx=edge[u].to;
        if(nx==n)
            ans=min(ans,tt.first);
        tts=p[nx].size();
        for(int k=0; k<tts; k++)
        {
            ll ts=dist[u]+p[nx][k].v+fabs(edge[u].id-p[nx][k].id);
            if(dist[p[nx][k].edg]>ts)
            {
                dist[p[nx][k].edg]=ts;
                tep.first=ts;
                tep.second=p[nx][k].edg;
                q.push(tep);
            }
        }
    }
    printf("%lld\n",ans);
}
int main()
{
    ll x,y,z,c;
    while(~scanf("%lld%lld",&n,&m))
    {
        top=0;
        for(int i=1; i<=n; i++)
            p[i].clear();
        for(int i=0; i<m; i++)
        {
            scanf("%lld%lld%lld%lld",&x,&y,&c,&z);
            edge[top].to=x;
            edge[top].v=z;
            edge[top].id=c;
            edge[top].edg=top;
            top++;
            p[y].push_back(edge[top-1]);
            edge[top].to=y;
            edge[top].v=z;
            edge[top].id=c;
            edge[top].edg=top;
            top++;
            p[x].push_back(edge[top-1]);
        }
        dijst();
    }
    return 0;
}

临界表存图

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<queue>
#include<vector>
#include<map>
#include<string>
#include<set>
#define LL long long
#define MAX(a,b) (a>b?a:b)
#define MIN(a,b) (a<b?a:b)
#define INF ((1<<31)-1)
#define LNF ((1LL<<62)-1)
#define maxn 200010
 
using namespace std;
 
int n,m,vis[maxn],head[maxn],tot;
LL d[maxn];
 
struct Node //记录边的信息
{
    int v,c,t,next;
}edge[maxn];
 
void Addedge(int u, int v, int c, int t) //将与u相连通的串在一起,可以用vector
{
    edge[tot].v = v;
    edge[tot].c = c;
    edge[tot].t = t;
    edge[tot].next = head[u];
    head[u] = tot++;
}
 
void init()
{
    memset(head,-1,sizeof(head));
    tot = 0;
}
 
LL dij()
{
    priority_queue< pair<LL,int> >q;  //队列记录花费的时间以及当前边的编号
    memset(vis,0,sizeof(vis));
 
    for(int i = 0; i<tot; i++)
        d[i] = LNF;
 
    for(int i = head[1]; i!=-1; i = edge[i].next)  //初始化,顶点1作为u的边入队
    {
        d[i] = edge[i].t;
        q.push(make_pair(-d[i],i));  //因为优先队列从大到小排,所以要加个负号,使其从小到大排列
    }
 
    while(!q.empty())
    {
        pair<LL,int>tmp = q.top();
        q.pop();
        int now = tmp.second;  //取边的编号
        vis[now] = 1;
 
        int u = edge[now].v;
        if(u==n) return d[now];  //如果当前边的v为顶点n,则找到最短路径
 
        for(int i = head[u]; i!=-1; i = edge[i].next)  //松弛
        {
            int v = edge[i].v;
            if(!vis[i] && d[i]>d[now]+edge[i].t + abs(edge[i].c - edge[now].c))  //abs(***)为转站花费的时间,如果相同,即为0
            {
                d[i] = d[now] + edge[i].t + abs(edge[i].c - edge[now].c);
                q.push(make_pair(-d[i],i));
            }
        }
    }
}
 
int main()
{
    int u,v,c,t;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        init();
        for(int i = 0; i<m; i++)
        {
            scanf("%d%d%d%d",&u,&v,&c,&t);
            Addedge(u,v,c,t);
            Addedge(v,u,c,t);
        }
        printf("%lld\n",dij());
    }
}
#include <iostream>
#include <algorithm>
#include <stdlib.h>
#include <math.h>
#include <string>
#include <string.h>
#include <stdio.h>
#include <queue>
 
using namespace std;
const int maxn=1e5;
typedef long long int LL;
const LL INF=0x3f3f3f3f3f3f3f3f;
struct node
{
    int next;
    int value;
    LL weight;
    LL c;
}edge[maxn*2+5];
int head[maxn*2+5];
int tot;
int vis[maxn+5];
LL d[maxn*2+5];
int n,m;
void add(int x,int y,int w,int c)
{
    edge[tot].value=y;
    edge[tot].weight=w;
    edge[tot].c=c;
    edge[tot].next=head[x];
    head[x]=tot++;
}
struct Node
{
    int id;
    LL dis;
    Node(){};
    Node(int id,LL dis)
    {
        this->id=id;
        this->dis=dis;
    }
    friend bool operator <(Node a,Node b)
    {
        return a.dis>b.dis;
    }
};
LL Dijkstra()
{
    priority_queue<Node> q;
    for(int i=0;i<tot;i++)
        d[i]=INF;
    LL ans=INF;
    for(int i=head[1];i!=-1;i=edge[i].next)
    {
        d[i]=edge[i].weight;
        q.push(Node(i,d[i]));
    }
    while(!q.empty())
    {
        Node term=q.top();
        q.pop();
        int p=edge[term.id].value;
 
        if(p==n)
            ans=min(ans,term.dis);
        for(int i=head[p];i!=-1;i=edge[i].next)
        {
            if(d[i]>term.dis+edge[i].weight+abs(edge[i].c-edge[term.id].c))
            {
                d[i]=term.dis+edge[i].weight+abs(edge[i].c-edge[term.id].c);
                q.push(Node(i,d[i]));
            }
            
        }
        
    }
    return ans;
}
int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        int x,y,w,c;
        memset(head,-1,sizeof(head));
        tot=0;
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%d%d",&x,&y,&c,&w);
            add(x,y,w,c);
            add(y,x,w,c);
        }
       
        printf("%lld\n", Dijkstra());
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41049928/article/details/82619948
今日推荐