题目:
C 城有 n 个站点, m 条双向地铁,每条地铁有一个 companyicompany_icompanyi表示它的公司,如果连续乘坐同一家公司的地铁只要花 1元钱就好。DD现在想出门找萨摩耶玩,但是 DD 是贫困人口, 她想知道最少花费多少钱能从 1 号点前往 n 号点
输入格式
第一行两个整数分别表示 n,m
接下来 m 行每行 3 个整数,分别表示地铁的起点终点和公司
输出格式
输出 DD 的最少花费是多少
数据范围
对于 30%30\%30% 的数据, n≤100,c≤100n \leq 100,c \leq 100n≤100,c≤100
对于另外 20%20\%20% 的数据, n≤105,c≤1n \leq 10^5,c \leq 1n≤105,c≤1对于 100%100\%100% 的数据, n,c≤105,m≤2×105n,c \leq 10^5,m \leq 2 \times 10^5n,c≤105,m≤2×105输出时每行末尾的多余空格,不影响答案正确性
样例输入
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 5
样例输出
2
分析:
本人小菜菜一枚,计蒜客面试题,这道我搞了三四个小时没搞出来,最后大佬出手,就知有木有哈,竟然是走边,orz%%%%%%%%,下面来分析哈。
1.首先看数据范围,就知道开二维数组是不得行的(除了用容器 map,vector啥的),那么这里就用邻接表,记录每一条边和点,顺便由边(tot),可以直接记录这个边上是哪家公司的车车在跑;
2.接着用优先队列建一个小根堆,里面的两个数据分别为x:与1号点连通的x号点;y:1~x点间交换过多少次公司;
3.因为建的是小根堆,每次拿出栈顶的是最小交换公司次数,所以每次存在一个与1不连通的点,进队列都更新次数,直到到达n号点。
AC代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;const int N=1e5+10;
const int M=4e5+10;int n,m;
int tot,fir[N];
int nex[M],to[M],id[M];
void add(int x,int y,int z){++tot;to[tot]=y; id[tot]=z;nex[tot]=fir[x]; fir[x]=tot;
}bool vis[M];
int dis[M];
struct node{int x,y;/**node(){}node(int x,int y):x(x),y(y){}*/bool operator<(const node&a)const{return y>a.y;}
};
priority_queue<node> Q;int dij(int sr){memset(vis,0,sizeof(vis));memset(dis,0x3f,sizeof(dis));while(!Q.empty()) Q.pop();for(int i=fir[sr]; i; i=nex[i]){dis[i]=1;Q.push((node){i,1});//Q.push(node(i,1));}while(!Q.empty()){int d=Q.top().x;Q.pop();if(vis[d]) continue;vis[d]=1;int u=to[d];if(u==n) return dis[d];for(int i=fir[u]; i; i=nex[i]){int t=(id[i]==id[d])?0:1;if(!vis[i] && dis[i]>dis[d]+t){dis[i]=dis[d]+t;Q.push((node){i,dis[i]});// Q.push(node(i,dis[i]));}}}return -1;
}int main()
{scanf("%d%d",&n,&m);for(int i=0; i<m; ++i){int t1,t2,t3;scanf("%d%d%d",&t1,&t2,&t3);add(t1,t2,t3); add(t2,t1,t3);}int ans=dij(1);printf("%d\n",ans);return 0;
}