题意:给你n个点, m条边(双向), 每条边有一个编号,求从1到n的最短路。如果没有则输出-1.
规则:经过一条边,花费为1,若经过的下一条边与当前的边编号相同,则下一条边不需要花费, 如果不同则代价+1.
简单来说就是 求 换乘次数+1
例1:
1-2 的编号 为1
1-3 的编号为2
2-3 的编号为1
则最短路 可以是 1-2-3 这里的编号都为1 所以答案为1 也可以是1-3的编号为2 也是代价为1
之前自己写的第一次写法有个很大的错误, 却在比赛中A了, 原因是hdu的数据出的不够严谨, 当时也没多想, 赛后写ac代码, 被评论的数据给hack了, 才知道自己的错误在哪里,菜啊
题解:用优先队列按每个点的最后一条的权值大小进行排序, bfs跑一遍最短路。
正解代码:
#include<bits/stdc++.h>
#define ll long long
#define line printf("=============\n");
#define inf 0x3f3f3f3f
using namespace std;
const int maxn = 2e5+5;
int head[maxn], tot;
int dis[maxn];//记录起点到每个点的最短距离
int n, m;
struct edge {
int v, id, next;//边的终点 权值 下一条边
} edges[maxn<<2];
void addedge(int u, int v, int id) { //邻接表
edges[++tot] = (edge) {
v, id, head[u]
};
head[u] = tot;
edges[++tot] = (edge) {
u, id, head[v]
};
head[v] = tot;
}//加边
struct node {
int id, val, kind;//点的序号 到这个点的权值 到这个点最后一条边的id
node() {}
node(int _id, int _val, int _kind) : id(_id), val(_val), kind(_kind) {}
bool operator < (const node &p) const {//用于优先队列内结构体的排序
return val > p.val;
}
};
int bfs() {
priority_queue<node> q;
memset(dis, inf, sizeof(dis));
dis[1] = 0;
q.push((node){1, 0, -1});
node temp;
while(!q.empty()) {
temp = q.top();
q.pop();
if(temp.val > dis[temp.id]) {
continue;//当到这个点的权值大于到这个点的最短路 舍去这条路径
}
if(temp.id == n) {
return temp.val;// 到达终点n直接返回结果
}
for(int i = head[temp.id]; i; i = edges[i].next) {
//状态比较 进行松弛操作
if(dis[temp.id] + (edges[i].id != temp.kind) < dis[edges[i].v]) {
dis[edges[i].v] = dis[temp.id] + (edges[i].id != temp.kind);
q.push(node(edges[i].v, dis[edges[i].v], edges[i].id));
}
}
}
return -1;
}
void init() {
tot = 0;
memset(head, 0, sizeof(head));
}
int main() {
while(~scanf("%d%d", &n, &m)){
init();
if(m == 0){
printf("-1\n");
}else {
for(int i = 0; i < m; i++){
int u, v, id;
scanf("%d%d%d", &u,&v,&id);
addedge(u,v,id);
addedge(v,u,id);
}
printf("%d\n",bfs());
}
}
return 0;
}