赞
踩
ybt 1377:最优乘车(travel)
洛谷 P5767 [NOI1997] 最优乘车
注意:每行末尾的换行符可能是"\r\n"或"\n"。
首先建模。题目要求的是换乘次数的最小值,因此尝试把边和换乘的概念联系在一起。
该题中的巴士是“单程巴士”,因此该图是有向无权图。该问题中的“最短路径”指的是有向无权图中的最短路径,即两点之间路径上边的条数。以巴士站为顶点,如果两顶点之间有边,说明两巴士站之间有直达的巴士线路。
如果两顶点之间最短路径长度为1,那么换乘次数是0。
如果两顶点之间最短路径长度为2,那么换乘次数是1。
…
如果两顶点之间最短路径长度为x,那么换乘次数是x-1。
输入时,一条线路上任何两顶点之间都要从前面的顶点向后面的顶点连一条有向边。
使用广搜可以求无权图上的最短路径问题,复杂度不超过为
O
(
V
2
)
O(V^2)
O(V2)。
用广搜求顶点1到顶点n的最短路径
对于无权图,可以将该图每条边的权值都视为1,而后就可以使用Floyd,Dijkstra,SPFA等方法求解。
本题解只展示Floyd算法,其他算法不再赘述。
【注意】由于每行末尾可能是"\r\n",因此在输入第一行m与n后,需要去掉本行的换行符时,不能只写一句cin.get()
(或getchar()
),因为当结尾是"\r\n"时,只会读入"\r",还留下了"\n"。
这里可以使用getline(cin, s)
读入整行一直读完本行的’\n’,或写if(cin.get() == '\r')cin.get();
。
#include<bits/stdc++.h> using namespace std; #define N 505 struct Node { int v, d;//v:顶点 d:到起始点的距离 Node(){} Node(int a, int b):v(a), d(b){} }; bool vis[N];//vis[i]:顶点i是否已访问过 int n, edge[N][N];//n:顶点数, edge:邻接矩阵 int bfs()//返回值:顶点1到顶点n的最短路径长度,如果找不到,返回-1。 { queue<Node> que; vis[1] = true; que.push(Node(1, 0)); while(que.empty() == false) { int u = que.front().v, d = que.front().d; que.pop(); if(u == n)//找到解 return d; for(int i = 1; i <= n; ++i) { if(edge[u][i] && vis[i] == false) { vis[i] = true; que.push(Node(i, d+1)); } } } return -1; } int main() { string s; int a, m;//m:巴士线路数量 cin >> m >> n; getline(cin, s);//读掉末尾的换行符,注意不能用cin.get(),因为末尾可能是"\r\n" for(int k = 1; k <= m; ++k) { vector<int> vec; getline(cin, s); stringstream ss(s); while(ss >> a) vec.push_back(a); for(int i = 0; i < vec.size()-1; ++i)//枚举vec中的所有数对 for(int j = i+1; j < vec.size(); ++j) edge[vec[i]][vec[j]] = 1;//为每个数对都建单向边 } int len = bfs();//最短路径长度 if(len == -1)//没有找到最短路径 cout << "NO"; else cout << len-1;//换车次数是路径长度减一 return 0; }
#include<bits/stdc++.h> using namespace std; #define INF 0x3f3f3f3f #define N 505 bool vis[N];//vis[i]:顶点i是否已访问过 int n, edge[N][N], dis[N][N];//n:顶点数, edge:邻接矩阵 void floyd() { memset(dis, 0x3f, sizeof(dis)); for(int i = 1; i <= n; ++i) for(int j = 1; j <= n; ++j) { if(i == j) dis[i][j] = 0; if(edge[i][j]) dis[i][j] = edge[i][j]; } for(int k = 1; k <= n; ++k) for(int i = 1; i <= n; ++i) for(int j = 1; j <= n; ++j) dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]); } int main() { string s; int a, m;//m:巴士线路数量 cin >> m >> n; getline(cin, s);//读掉末尾的换行符,注意不能用cin.get(),因为末尾可能是"\r\n" for(int k = 1; k <= m; ++k) { vector<int> vec; getline(cin, s); stringstream ss(s); while(ss >> a) vec.push_back(a); for(int i = 0; i < vec.size()-1; ++i)//枚举vec中的所有数对 for(int j = i+1; j < vec.size(); ++j) edge[vec[i]][vec[j]] = 1;//为每个数对都建单向边 } floyd(); if(dis[1][n] == INF)//没有找到最短路径 cout << "NO"; else cout << dis[1][n]-1;//换车次数是路径长度减一 return 0; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。