csu1808: 地铁(边看为点最短路)

Description

 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

题意:每个边都有一个线路,在站点换线的代价是两线的差值的绝对值,问1-n最短路.

思路:我们把边看为点,但是如果一个点两边各有1e5个线路,是不可能建这么多边的,所以我们可以每次只对一个点建边(这里的点就是原图的边),建的边的目标就是原图中这条边所连得点的所连得边,然后每次从优先队列里取出最小的那个来,这样他就可以被标记了,以后再也不用走来这了,也就是说下次有点想往这建边我们完全可以不建,这样不就节省了大量空间了嘛!

代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<stack>
#include<cstring>
#include<string>
#include<vector>
#include<cmath>
#include<map>
#include<set>
#define mem(a,b) memset(a,b,sizeof(a))
#define mod 1000000007
using namespace std;
typedef long long ll;
const int maxn = 1e6+500;
const double esp = 1e-7;
const int ff = 0x3f3f3f3f;
map<int,int>::iterator it;
struct node
{
	int u;
	int v;
	ll w;
	int ne;
	int line;
}edge[maxn];

int n,m,len;
int vis[maxn];
int head[maxn];
ll dis[maxn];

void add(int u,int v,int line,ll w)
{
	edge[len].u = u;
	edge[len].v = v;
	edge[len].w = w;
	edge[len].line = line;
	edge[len].ne = head[u];
	head[u] = len++;
}

ll DJ()
{
	priority_queue< pair<ll,int>, vector<pair<ll,int> >, greater<pair<ll,int> > > q;
	
	for(int i = head[1];i!= -1;i = edge[i].ne)
	{
		dis[i] = edge[i].w;
		q.push(make_pair(dis[i],i));
	}
	
	while(!q.empty())
	{
		pair<ll,int> it = q.top();
		q.pop();
		
		int now = it.second;
		
		if(edge[now].v == n)
			return dis[now];
		
		if(vis[now]) continue;
		vis[now] = 1;
		
		for(int i = head[edge[now].v];i!= -1;i = edge[i].ne)
		{
			if(dis[i]> dis[now]+abs(edge[now].line - edge[i].line)+edge[i].w)
			{
				dis[i] = dis[now]+abs(edge[now].line - edge[i].line)+edge[i].w;
				q.push(make_pair(dis[i],i));
			}
		}
	}
	
	return -1;
}

void init()
{
	len = 0;
	mem(vis,0);
	mem(head,-1);
	for(int i = 0;i< maxn;i++)
		dis[i] = 1e16;
}

int main()
{
	while(~scanf("%d %d",&n,&m))
	{
		init();
		for(int i = 1;i<= m;i++)
		{
			int a,b,c,t;
			scanf("%d %d %d %d",&a,&b,&c,&t);
			add(a,b,c,t);
			add(b,a,c,t);
		}
		
		printf("%lld\n",DJ());
	}
	
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值