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;
}