题意:给你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;
}  

 京公网安备 11010502036488号
京公网安备 11010502036488号