题目背景
济南地铁已经开通了R1和R3线。
小李白也兴奋地在高考前去体验了一下,发现可以用公交卡刷卡并且车站文化氛围很浓厚qwq
题目描述
小李白来到了一个大城市,他住在了一个五星级酒店,他规划着接下来的几天内在大城市的城区内坐地铁游玩景点。这个城市有着完善的地铁网络。但是非常不幸的是,地铁全是单向行驶的。
小李白每天都要坐地铁去一个景点游玩,然后傍晚时分坐地铁回来。第一天去编号为2的景点,第二天去编号为3的景点......小李白要去过所有的景点才会罢休qwq。我们设每一个地铁站点都是一个景点。对于每一天的景点,小李白都想知道如何坐地铁才能使得来回总时间合最小。他会给你整个城市的地铁路线和站点图,并且向你求助这个问题。
有n个站点,m个站点间的地铁线路。小李白所住的酒店需要耗时时间d才能到地铁站1,也就是从站点1开始坐地铁。
数据会给你每对站点之间的路线长度w.
输入格式
第1行:n,m,d
第2到m+1行,u,v,w,表示从站点u到站点v有一条长度为w的地铁路线。
输出格式
小李白每天在路上耗时的和sum。 为了更方便的解释,我们设每天在路上花费的时间为time[i],小李白要去的景点数为k。
那么答案就是∑i=1ktime[i]。
输入输出样例
说明/提示
对于30%的数据,n=1
对于100%的数据:
n⩽1000
m⩽100000
w⩽200
d⩽1500000
均为整数。
小李白远远不如他的朋友ych强,所以只能结合高考前放假经历随便出了个题
注意空间时间限制qwq。
思路:
参观每一个景点都要从一号车站过去再回来,所以很明显是一个单源最短路,因为没有负边权,所以可以使用比SPFA更快的Dijkstra算法来求单源最短路。但是从各个景点回来的时候应该怎么办呢?通过dalao的题解,我学会了建反边这一个神奇的操作。因为每次从景点回来都是回到一号车站,都是那一个点,所以如果在另一张新图里反向建边,就可以再跑一遍Dijkstra,从而转化为单源最短路(妙啊)
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #include<queue> using namespace std; const int N=1005,M=100005; long long n,m,k,tot1,tot2,ans; long long Next1[M],ver1[M],edge1[M],head1[N],d1[N],Next2[M],ver2[M],edge2[M],head2[N],d2[N];//不开longlong见祖宗 bool v1[N],v2[N]; priority_queue< pair <int,int> >q1; priority_queue< pair <int,int> >q2;//因为要存两个图,所以什么变量都开两遍 void add1(long x,long long y,long long z){ ver1[++tot1]=y;//编号为tot的边的终点是y edge1[tot1]=z;//边权是z Next1[tot1]=head1[x];//新加入的边的下一条边是原本与x相连的第一条边 head1[x]=tot1;//链式前向星结构,把新加入的边放到与x相连接的第一条边 } void add2(long long x,long long y,long long z){ ver2[++tot2]=y; edge2[tot2]=z; Next2[tot2]=head2[x]; head2[x]=tot2; } void dijkstra1(long long x){ memset(d1,0x3f,sizeof(d1));//把起点到所有点的距离都初始化为无穷大,保证能更新 memset(v1,0,sizeof(v1));//一开始所有点都没有到过 d1[x]=0;//自己到自己的距离当然是0 q1.push(make_pair(0,x));//pair的第一维表示点x到起点的距离,第二维表示点的编号x while(q1.size()!=0){//当堆不为空 long long x=q1.top().second;//取出第二维点的编号 q1.pop();//弹出 if(v1[x]==1) continue;//如果这个点已经被访问过了,那么继续循环 v1[x]=1;//如果没有访问过那么标记为访问过 for(long long i=head1[x];i;i=Next1[i]){//链式前向星遍历 long long y=ver1[i],z=edge1[i]; if(d1[y]>d1[x]+z){//松弛操作 d1[y]=d1[x]+z; q1.push(make_pair(-d1[y],y));//加入堆中,因为STL中提供的是大根堆,我们要用小根堆,所以把距离的相反数存进去排序,就相当于是小根堆了 } } } } void dijkstra2(long long x){ memset(d2,0x3f,sizeof(d2)); memset(v2,0,sizeof(v2)); d2[x]=0; q2.push(make_pair(0,x)); while(q2.size()!=0){ long long x=q2.top().second; q2.pop(); if(v2[x]==1) continue; v2[x]=1; for(long long i=head2[x];i;i=Next2[i]){ long long y=ver2[i],z=edge2[i]; if(d2[y]>d2[x]+z){ d2[y]=d2[x]+z; q2.push(make_pair(-d2[y],y)); } } } } int main() { scanf("%lld%lld%lld",&n,&m,&k); for(long long i=1,x,y,z;i<=m;i++){ scanf("%lld%lld%lld",&x,&y,&z); add1(x,y,z); add2(y,x,z);//反着建边 } ans=(n-1)*k*2;//每天从酒店到一号车站所要走的距离 dijkstra1(1); dijkstra2(1);//跑两遍Dijkstra for(long long i=1;i<=n;i++){ ans+=d1[i]+d2[i];//把来回的距离和加起来 } printf("%lld ",ans); return 0; }