1377:最优乘车(travel)
时间限制: 1000 ms 内存限制: 65536 KB
提交数: 12377 通过数: 2989
【题目描述】
H城是一个旅游胜地,每年都有成千上万的人前来观光。为方便游客,巴士公司在各个旅游景点及宾馆,饭店等地都设置了巴士站并开通了一些单程巴士线路。每条单程巴士线路从某个巴士站出发,依次途经若干个巴士站,最终到达终点巴士站。
一名旅客最近到H城旅游,他很想去S公园游玩,但如果从他所在的饭店没有一路巴士可以直接到达S公园,则他可能要先乘某一路巴士坐几站,再下来换乘同一站台的另一路巴士, 这样换乘几次后到达S公园。
现在用整数1,2,…N 给H城的所有的巴士站编号,约定这名旅客所在饭店的巴士站编号为1,S公园巴士站的编号为N。
写一个程序,帮助这名旅客寻找一个最优乘车方案,使他在从饭店乘车到S公园的过程中换车的次数最少。
【输入】
第一行有两个数字M和N(1<=M<=100 1<N<=500),表示开通了M条单程巴士线路,总共有N个车站。从第二行到第M行依次给出了第1条到第M条巴士线路的信息。其中第i+1行给出的是第i条巴士线路的信息,从左至右按运行顺序依次给出了该线路上的所有站号相邻两个站号之间用一个空格隔开。
【输出】
只有一行。如果无法乘巴士从饭店到达S公园,则输出"N0",否则输出你的程序所找到的最少换车次数,换车次数为0表示不需换车即可到达。
【输入样例】
3 7
6 7
4 7 3 6
2 1 3 5
【输出样例】
2
思路
1.我们先来根据样例来建个图(颜色不同代表的线路不同,红:1,橙:2,粉:3)
由样例图可以看出,1->7的最少换乘的次数是2次:1->3 换乘 3->6 换乘 6->7
是这样建图吗?
No No No,这样马上就成模拟了
2.我们可以这样建图:在前面的图的基础上将每一条线路的站点,都与这条线路前面的相连(也就是添边)
然后,我们的图就变成了这样:
这样我们就可以直接用Dijkstra求出最短路,再用最短路-1就可以求出换乘次数(也就是最终答案)
可以直接添边?Why?
Because我们加边只跟同一条线路上的点有关,不会影响线路的条数,也就是说不会影响我们的最终答案
将每个点都与前面的点相连,是因为不能确定后来读入的线路是否与前面的线路存在换乘点,所以就全连上。
我们的 重要添边代码闪亮登场了
for(int z=1;z<=p;z++){
for(int j=z+1;j<=p;j++){
a[arr[z]][arr[j]]=1;//边权都设为1
}
}
3.最后,我们的最终代码
#include<bits/stdc++.h>
using namespace std;
bool flag[1005];
int dist[1005],n,p=1,k,numb,m,a[1005][1005],arr[1005];
string s;
void Dijkstra(){
for(int i=1;i<=n;i++){
dist[i]=a[1][i];
}
dist[1]=0;
flag[1]=true;
for(int i=1;i<=n-1;i++){
int maxv=0x3f3f3f3f;
for(int j=1;j<=n;j++){
if(!flag[j]&&dist[j]<maxv){
k=j;
maxv=dist[j];
}
}
if(maxv>=0x3f3f3f3f){
break;
}
flag[k]=true;
for(int j=1;j<=n;j++){
if(dist[j]>dist[k]+a[k][j]){
dist[j]=dist[k]+a[k][j];
}
}
}
}
void fl(int p) {
for(int z=1;z<=p;z++){
for(int j=z+1;j<=p;j++){
a[arr[z]][arr[j]]=1;
}
}
}
int main(){
cin>>m>>n;
memset(dist,0x3f,sizeof(dist));
memset(a,0x3f,sizeof(a));
for(int i=1;i<=m+1;i++){
getline(cin,s);
for(int j=0;j<s.size();j++){
if('0'<=s[j]&&s[j]<='9'){
int num=s[j]-'0';
numb=numb*10+num;
}else{
arr[p]=numb;
numb=0;
p++;
}
}
arr[p]=numb;
fl(p);
p=1;
numb=0;
}
Dijkstra();
if(dist[n]>=0x3f3f3f3f){
cout<<"NO";
}else{
cout<<dist[n]-1;
}
return 0;
}