題目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; }