Age of Moyu
Time Limit: 5000/2500 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 1962 Accepted Submission(s): 603
Problem Description
Mr.Quin love fishes so much and Mr.Quin’s city has a nautical system,consisiting of N ports and M shipping lines. The ports are numbered 1 to N. Each line is occupied by a Weitian. Each Weitian has an identification number.
The i-th (1≤i≤M) line connects port Ai and Bi (Ai≠Bi) bidirectionally, and occupied by Ci Weitian (At most one line between two ports).
When Mr.Quin only uses lines that are occupied by the same Weitian, the cost is 1 XiangXiangJi. Whenever Mr.Quin changes to a line that is occupied by a different Weitian from the current line, Mr.Quin is charged an additional cost of 1 XiangXiangJi. In a case where Mr.Quin changed from some Weitian A's line to another Weitian's line changes to Weitian A's line again, the additional cost is incurred again.
Mr.Quin is now at port 1 and wants to travel to port N where live many fishes. Find the minimum required XiangXiangJi (If Mr.Quin can’t travel to port N, print −1instead)
Input
There might be multiple test cases, no more than 20. You need to read till the end of input.
For each test case,In the first line, two integers N (2≤N≤100000) and M (0≤M≤200000), representing the number of ports and shipping lines in the city.
In the following m lines, each contain three integers, the first and second representing two ends Ai and Bi of a shipping line (1≤Ai,Bi≤N) and the third representing the identification number Ci (1≤Ci≤1000000) of Weitian who occupies this shipping line.
Output
For each test case output the minimum required cost. If Mr.Quin can’t travel to port N, output −1 instead.
Sample Input
3 3
1 2 1
1 3 2
2 3 1
2 0
3 2
1 2 1
2 3 2
Sample Output
1
-1
2
题目大意:
给你n和m,代表有n个港口,还有m条航线。每条航线上都被其中一家公司承包了。假设你最开始走的是1号公司的航线,你要支付1块钱,但是当你下次还是走1公司的航线的时候,就不需要给钱了;如果你走的不是1公司的,是3公司的,那么就要重新给1块钱。
解法:
根据题意,给出的m条航线是双向边,也就是无向图,我们要建两次边,也就是说假设有a->b航线,那么我们还要反着建一条航线b->a。然后跑一遍bfs,相同航线的去dfs寻找,不行的就可以换一条航线去寻找。因为是以bfs为基础去dfs,所以先找到的就是需要最少交换航线公司的次数。(弱鸡自闭了一下午,看了大佬的代码才能写出来,嘤嘤嘤~)
#include <bits/stdc++.h>
#include <queue>
#define MAXN 100005
using namespace std;
struct KNIGHT{
int a,b,c,next;
bool vis;//判断是否访问过
}p[MAXN << 2];
int head[MAXN],mark[MAXN],dis[MAXN];//mark数组判断是否访问过,dis数组计算要变换航线的次数
int num,n,m,a,b,c,ans;
queue<int>q;
void addedge(int a,int b,int c){
p[num].a = a;
p[num].b = b;
p[num].c = c;
p[num].next = head[a];//把起点为a的全部连起来,方便查询
p[num].vis = false;
head[a] = num++;//head数组可以记录最后一个出现起点为a的下标
}
void dfs( int b , int c , int money ){
if(b == n){
ans = money;
return;
}
if(!mark[b]){
q.push(b);
mark[b] = true;
dis[b] = money;
}
for(int i = head[b] ; i != -1 ; i = p[i].next ){
if(p[i].vis)
continue;
if(p[i].c == c){
p[i].vis = true;
dfs( p[i].b , c , money );
}
}
return;
}
int bfs(){
while(!q.empty())
q.pop();
q.push( 1 );
mark[1] = 1;
dis[1] = 0;
while(!q.empty()){
int tep = q.front();
q.pop();
for(int i = head[tep] ; i != -1 ; i = p[i].next){
if( p[i].vis )
continue;
p[i].vis = true;
dfs( p[i].b , p[i].c , dis[tep] + 1 );
if(ans > 0)
break;
}
if(ans > 0)
break;
}
return ans;
}
void init(){//初始化
num = 0; ans = -1;
memset(head, -1, sizeof(head));
memset(mark, false, sizeof(mark));
memset(dis, 0x3f3f3f3f, sizeof(dis));
}
int main(){
while( scanf("%d%d", &n, &m) != EOF ){
init();
for(int i = 1; i <= m; i++){
scanf("%d%d%d", &a, &b, &c);
addedge( a , b , c );//双向边,所以反着也要建一条边
addedge( b , a , c );
}
printf("%d\n", bfs());
}
}