思路和大部分题解有些不同。建边时,大部分题解都是把同一条航线上的点两两相连,而我是只将相邻的两个点连接起来,并记录航线编号。我用的是 SPFA 求的最短路。详见代码注释。
#include<bits/stdc++.h>
#define int long long int
using namespace std;
int a[1010]/*航线花费*/,d[1010]/*各点到起点的最小花费*/,e[1010]/*在最小花费的基础上,各点到起点的最小城市数*/,m/*航线数*/,n/*城市数*/,x/*起点*/,xx,y/*终点*/,yy;
vector<pair<int,int> >b[1010];//边,i为起点,first为终点,second为航线编号
bool c[1010];//SPFA判断是否在队列中
queue<pair<int,int> >q;//SPFA队列,first为当前城市,second为是从哪条航线来的
signed main(){
ios::sync_with_stdio(0);
cin>>x>>y>>n;
for(register int i=1;i<=n;i++){
cin>>a[i]>>m;
xx=0;//同航线上个城市
while(m--){
cin>>yy;//当前城市
b[xx].push_back({yy,i});//同航线上个城市可通过航线i达到当前城市
xx=yy;//同航线上个城市
}
}
c[x]=1;//起点入队
for(register int i=1;i<=1000;i++) d[i]=LONG_LONG_MAX;//距离初始化
d[x]=0;//距离初始化
q.push({x,0});//起点入队,由于航线编号为1~n,起点并未从任何航线过来,故令航线为0
while(!q.empty()){//SPFA
xx=q.front().first;//当前城市
yy=q.front().second;//当前航线
q.pop();
c[xx]=0;//SPFA出队
for(register int i=0;i<b[xx].size();i++){
if(d[xx]+bool(yy!=b[xx][i].second)*a[b[xx][i].second]/*若不在同一航线,则需加此航线花费*/<d[b[xx][i].first]/*花费更少*/||d[xx]+bool(yy!=b[xx][i].second)*a[b[xx][i].second]==d[b[xx][i].first]&&e[xx]+1<e[b[xx][i].first]/*花费相同,但经过城市数更少*/){
d[b[xx][i].first]=d[xx]+bool(yy!=b[xx][i].second)*a[b[xx][i].second];
e[b[xx][i].first]=e[xx]+1;//松弛更新
if(!c[b[xx][i].first]){
c[b[xx][i].first]=1;
q.push({b[xx][i].first,b[xx][i].second});
}//入队
}
}
}
if(d[y]==LONG_LONG_MAX) cout<<"-1 -1";
else cout<<d[y]<<' '<<e[y];
return 0;
}