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≤i≤M ) 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≤pi≤N (1≤i≤M)
- 1≤qi≤N (1≤i≤M)
- 1≤ci≤106 (1≤i≤M)
- pi≠qi (1≤i≤M)
Input
The input is given from Standard Input in the following format:
N M
p1 q1 c1
:
pM qM cMOutput
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 2Sample 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 5Sample 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;
}