题意:有n个点,m条环路线,每条路线有若干个点且有一辆车b在环线上不断运行,每辆车0时刻从路线的起点出发,到下一点需要若干时间。从一条线路切换到另一条线路需要两辆车同时同地,现在求从点1到其他各个点的最小时间。
#include<bits/stdc++.h>
using namespace std;
struct Node
{
int lineid; // 线路id
int pointid; // 线路上的站点id
int d; // 当前点到起点的距离
};
vector<Node> point[510];//记录点i在哪一条路线上
vector<pair<int,int>> line[510];//记录下一个站点和需要的时间
long long times[510];//路线总长度
long long dis[510],ans[510];
int vis[510],First[510];//第i条路线最早得到疫苗的点
int n,m,num;
long long gcd(long long a,long long b,long long &x,long long &y)
{
if(b==0){x=1;y=0;return a;}
long long d=gcd(b,a%b,y,x);
y=y-a/b*x;
return d;
}
void Dij()
{
memset(dis,0x3f,sizeof(dis));
for(int i=0;i<m;i++)
{
int D=0;
for(int j=0;j<line[i].size();j++)
{
if(line[i][j].first==1)//找到线路i上的第j个点站点号是1作为起点
{
dis[i]=D;
First[i]=j;break;
}
D+=line[i][j].second;
}
}
for(int i=0;i<m;i++)
{
int temp=-1;
for(int j=0;j<m;j++)
if(vis[j]!=1&&(temp==-1||dis[j]<dis[temp]))temp=j;
long long d=dis[temp];
vis[temp]=1; //这里要注意j不一定从0开始,所以走完一条路线需要另一个k来记录
for(int j=First[temp],k=0;k<line[temp].size();k++,j=(j+1)%line[temp].size())//走同一条路线
{ //line[temp][j].first存储的才是题目中站点的编号
for(int l=0;l<point[line[temp][j].first].size();l++)//先找可不可以转到不同路线
{
Node T=point[line[temp][j].first][l];
if(vis[T.lineid]==1)continue;
long long a=d,b=times[temp];
long long x=T.d,y=times[T.lineid];
long long X,Y;
long long Dis=gcd(b,y,X,Y);
if((x-a)%Dis)continue;
X=(x-a)/Dis*X;y/=Dis;X=(X%y+y)%y;
if(dis[T.lineid]>a+b*X)
{
dis[T.lineid]=a+b*X;
First[T.lineid]=T.pointid;
}
}
d+=line[temp][j].second;
}
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=0;i<m;i++)
{
scanf("%d",&num);int sum=0;
for(int j=0;j<num;j++)
{
int v,t;
scanf("%d%d",&v,&t);
pair <int,int>temp;temp.first=v;temp.second=t;
point[v].push_back(Node{i,j,sum});
line[i].push_back(temp);
sum+=t;
}
times[i]=sum;
}
Dij();
memset(ans,0x3f,sizeof(ans));
for(int i=0;i<m;i++)
{
if(dis[i]==4557430888798830399)continue;
long long d=dis[i];
for(int j=First[i],k=0;k<line[i].size();k++,j=(j+1)%line[i].size())
{
int v=line[i][j].first;
ans[v]=min(ans[v],d);//同一路线上的点的最短路径不要忘记
d+=line[i][j].second;
}
}
for(int i=2;i<=n;i++)
{
if(ans[i]==4557430888798830399)printf("inf\n");
else printf("%lld\n",ans[i]);
}
return 0;
}