题目node
核心思路:Dijkstra算法c++
首先,我认为这道题最重要的是建图,解释一下我是如何建图:算法
(题目中说明了是“单程巴士线路”,故图为有向图。)spa
样例:
code
(线路的站点就是节点,边上的数字就是指这条边属于哪一条线路)blog
由样例图能够看出,1->7的最少换乘的次数是2次:字符串
1->3 换乘 3->6 换乘 6->7get
但若是只是单纯的做模拟,这道题就失去了意义。it
咱们不妨这样建图:模板
将每一条线路的站点,都与这条线路的起点相连。
在同一条线路上的节点,对于最后的换乘数是没有贡献的。 也就是说,同一条线路上的点是等价的。
而将每一个点都与起点相连,是由于不能肯定后来读入的线路是否与先前的线路存在换乘点。 因此干脆就全连上。
这样一来,图中1->n的最短路,就是最小换乘数+1。
而后,讲这道题如何读入。
我看已有的许多的题解中,是用字符串读入的。大可没必要。
咱们能够利用空格和换行符来读入。
像这样:
while(c!=-1 && c!='\r') //'\n' { scanf("%d",&a[ ++n ]); c=-1; scanf("%c",&c); }
(这个'/r'和洛谷的测评姬有关)
难度评分:建议绿题
理由:这题在Dijkstra模板题的基础上,增长了对Dijkstra的理解应用,同时这道题卡读入。
附上代码:
#include <bits/stdc++.h> #define MAXN 510 #define MAX 0x3f3f3f3f using namespace std; int ori=1,node; //ori 起点 node 节点数 int a[5005]; //存输入 int dis[MAXN],g[MAXN][MAXN]; bool vis[MAXN]; void init() //初始化 { memset(vis,0,sizeof(vis)); memset(dis,0,sizeof(dis)); vis[ori]=1; for(int i=1;i<=node;++i) dis[i] = (i == ori ? 0 : g[ori][i]); } void Dijkstra() //朴素Dijkstra { int k; init(); for(int i=1;i<=node-2;++i) { int m=MAX; for(int j=1;j<=node;++j) { if(dis[j]<m && vis[j]==0) {m=dis[j]; k=j;} } if(m==MAX) break; vis[k]=1; for(int j=1;j<=node;++j) if(dis[k]+g[k][j]<dis[j]) dis[j]=dis[k]+g[k][j]; } return ; } int main() { int edge; scanf("%d%d",&edge,&node); for(int i=1;i<=node;++i) for(int j=1;j<=node;++j) g[i][j]=MAX; for(int i=1;i<=edge;++i) { memset(a,0,sizeof(a)); int n=0; //计数器 char c=1; while(c!=-1 && c!='\r') //'\n' { scanf("%d",&a[ ++n ]); c=-1; scanf("%c",&c); } for(int j=1;j<n;++j) for(int k=j+1;k<=n;++k) g[ a[j] ][ a[k] ]=1; } Dijkstra(); if(dis[node]>=MAX) printf("NO"); else printf("%d",dis[node]-1); //换乘数为最短距离-1 return 0; }