求助
查看原帖
求助
1050072
a18981826590楼主2024/10/19 15:37

记录

思路和大部分题解有些不同。建边时,大部分题解都是把同一条航线上的点两两相连,而我是只将相邻的两个点连接起来,并记录航线编号。我用的是 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;
}
2024/10/19 15:37
加载中...