すぬけ君の地下鉄旅行 / Snuke's Subway Trip(AtCoder-2069)

Problem Description

Snuke's town has a subway system, consisting of N stations and M railway lines. The stations are numbered 1 through N. Each line is operated by a company. Each company has an identification number.

The i-th ( 1≤iM ) line connects station pi and qi bidirectionally. There is no intermediate station. This line is operated by company ci.

You can change trains at a station where multiple lines are available.

The fare system used in this subway system is a bit strange. When a passenger only uses lines that are operated by the same company, the fare is 1 yen (the currency of Japan). Whenever a passenger changes to a line that is operated by a different company from the current line, the passenger is charged an additional fare of 1 yen. In a case where a passenger who changed from some company A's line to another company's line changes to company A's line again, the additional fare is incurred again.

Snuke is now at station 1 and wants to travel to station N by subway. Find the minimum required fare.

Constraints

  • 2≤N≤105
  • 0≤M≤2×105
  • 1≤piN (1≤iM)
  • 1≤qiN (1≤iM)
  • 1≤ci≤106 (1≤iM)
  • piqi (1≤iM)

Input

The input is given from Standard Input in the following format:

N M
p1 q1 c1
:
pM qM cM

Output

Print the minimum required fare. If it is impossible to get to station N by subway, print -1 instead.

Example

Sample Input 1

3 3
1 2 1
2 3 1
3 1 2

Sample Output 1

1
Use company 1's lines: 1 → 2 → 3. The fare is 1 yen.

Sample Input 2

8 11
1 3 1
1 4 2
2 3 1
2 5 1
3 4 3
3 6 3
3 7 3
4 8 4
5 6 1
6 7 5
7 8 5

Sample Output 2

2
First, use company 1's lines: 1 → 3 → 2 → 5 → 6. Then, use company 5's lines: 6 → 7 → 8. The fare is 2 yen.

Sample Input 3

2 0

Sample Output 3

-1

题意:n 个点 m 条边,每条边给出邻接点的同时给出一个价值,代表的是该边所属的公司,现在要从 1 号点到 n 号点,已知在同一个公司上行走时,无需付出任何代价,但当走到令一公司的边上时,需要花费 1 元,求最小花费

思路:

这个题的问题在于让相同公司的道路之间行走花费为 0,不同公司之间的道路行走花费为 1,于是整张图的每个公司可以看做一个虚点,其连接着其所属的边的两点

由于在同一个公司的路上行走时,不耗费任何价值,那么可以对同一公司的路上进行拆点建图,即对于所属公司为 val 的边 x-y,将其拆成 x-newX、newX-newY、newY-y 三条边,其价值分别为 1、0、1,然后对整个图跑 SPFA 求最短路即可

跑完 SPFA 时,由于在起点时需要一个初始代价,中间行走时不需要代价,离开时也需要一个代价,因此 dis[n]/2 就是答案

此外,重点在于如何拆点能保证点不重复,考虑到 map 的特性,我们令 mp[a][b] 的值从 n 号点开始递增,从而保证点的唯一性

需要注意的是,由于拆完点后点和边的数目会很多,因此数组范围要开的大一点

Source Program

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<utility>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
#define EPS 1e-9
#define PI acos(-1.0)
#define INF 0x3f3f3f3f
#define LL long long
const int MOD = 1E9+7;
const int N = 1000000+5;
const int dx[] = {0,0,-1,1,-1,-1,1,1};
const int dy[] = {-1,1,0,0,-1,1,-1,1};
using namespace std;
struct Edge {
    int to,next,val;
    Edge(){}
    Edge(int to,int next,int val):to(to),next(next),val(val){}
    bool operator < (const Edge& rhs)const{
        return val>rhs.val;
    }
}edge[N*2];
int tot,head[N];
void addEdge(int from,int to,int val) {
    edge[tot].next=head[from];
    edge[tot].to=to;
    edge[tot].val=val;
    head[from]=tot++;
}
bool vis[N];
int dis[N];
int SPFA(int s,int e) {
    memset(vis,false,sizeof(vis));
    memset(dis,INF,sizeof(dis));
    dis[s]=0;

    priority_queue<Edge> Q;
    Q.push(Edge(s,0,0));
    while (!Q.empty()) {
        Edge temp=Q.top();
        Q.pop();
        if(vis[temp.to])
            continue;
        vis[temp.to]=true;

        for(int i=head[temp.to]; i!=-1; i=edge[i].next) {
            if(dis[edge[i].to]>dis[temp.to]+edge[i].val) {
                dis[edge[i].to]=dis[temp.to]+edge[i].val;
                Q.push(Edge(edge[i].to,0,dis[edge[i].to]));
            }
        }
    }
    if(dis[e]!=INF)
        return dis[e]/2;
    return -1;
}
map<int,int> mp[N];
int allPoint;
int getPoint(int x,int y) {
    if (!mp[x][y])
        mp[x][y]=++allPoint;
    return mp[x][y];
}
int main() {
    int n,m;
    scanf("%d%d",&n,&m);
    memset(head,-1,sizeof(head));
    allPoint=n;
    for (int i=1; i<=m; i++) {
        int x,y,w;
        scanf("%d%d%d",&x,&y,&w);

        int newX=getPoint(x,w);
        int newY=getPoint(y,w);

        addEdge(x,newX,1);
        addEdge(newX,x,1);
        addEdge(newX,newY,0);
        addEdge(newY,newX,0);
        addEdge(y,newY,1);
        addEdge(newY,y,1);
    }
    int res=SPFA(1,n);
    printf("%d\n",res);
    return 0;
}

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值