Age of Moyu
Time Limit: 5000/2500 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 3125 Accepted Submission(s): 981
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 −1 instead)
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
Source
2018 Multi-University Training Contest 7
Recommend
chendu | We have carefully selected several similar problems for you: 6408 6407 6406 6405 6404
#include<bits/stdc++.h>
using namespace std;
#define debug puts("YES");
#define rep(x,y,z) for(int (x)=(y);(x)<(z);(x)++)
#define read(x,y) scanf("%d%d",&x,&y)
const int maxn =2e5+5;
///BFS+优先队列的做法
///链式前向星
struct node{int u,nxt,w;};
node edge[maxn<<2];///链式前向星数组开两倍
int head[maxn],tot;
void init(){ memset(head,-1,sizeof(head)); tot=0; }
void add(int x,int y,int z) { edge[tot]=node{y,head[x],z} , head[x]=tot++; }
/*
题目大意:给定一个图,
边上有颜色序号区分,从不同的颜色需要经过答案权重加一,
问从1到n最小的权重是多少。
这道题的关键是如何剪枝,算法采用最短路的情况,
就是差分约束,每算出一个点就对其余相邻点做差分约束,
采用优先队列保证每次采用的都是最短距离的节点,
然后考虑会有这么个情况,
就是一个稍微长点的路径经过一个算出来的距离稍短的节点,
可能因为所经过的颜色不同而产生更优解,
所以标记一个点的代价时,不再和以前一样只是判别走没走过,
还要附带上前驱节点的集合,
如果发现更短,则清空当前节点的前驱集合,这是特别的地方。
集合用set来表示,不必含有相同的前驱节点集合
*/
int n,m,a,b,c;
///最短路结构体
struct road {
int dis,u;
int pre,fa;///记录前驱节点fa,pre记录上一次的轮胎记录
bool operator<(const road &y) const
{
return dis>y.dis;///优先级
}
};
set<int> sta[maxn];///这回用的不是vis数组去重了,而是判断前缀。
int dis[maxn];
int bfs()
{
for(int i=1;i<=n;i++) sta[i].clear();
memset(dis,0xf,sizeof(dis)); dis[1]=0;
priority_queue<road> pq;
pq.push(road{dis[1],1,-1,-1});
while(!pq.empty())
{
road tp=pq.top(); pq.pop();
int pre=tp.pre,u=tp.u,d=tp.dis;
if(d>dis[u]) continue;
else if(d==dis[u])
{
if(sta[u].find(tp.fa)!=sta[u].end()) continue;
sta[u].insert(tp.fa);
}
else
{
dis[u]=d;///更新距离数组
sta[u].clear();
sta[u].insert(tp.fa);
}
for(int i=head[u];~i;i=edge[i].nxt)
{
int v=edge[i].u,now=edge[i].w;
if(tp.fa==v) continue;
if(dis[v]>=dis[u]+(pre!=now))///差分约束
{
dis[v]=dis[u]+(pre!=now);
pq.push(road{dis[v],v,now,u});
}
}
}
return (dis[n]>=100007)?-1:dis[n];
}
int main()
{
while(read(n,m)!=EOF)
{
init();
for(int i=0;i<m;i++)
{
scanf("%d%d%d",&a,&b,&c);
add(a,b,c);
add(b,a,c);
}///建图
printf("%d\n",bfs());
}
return 0;
}