In the city of Dingilville the traffic is arranged in an unusual way. There are junctions and roads connecting the junctions. There is at most one road between any two different junctions. There is no road connecting a junction to itself. Travel time for a road is the same for both directions. At every junction there is a single traffic light that is either blue or purple at any moment. The color of each light alternates periodically: blue for certain duration and then purple for another duration. Traffic is permitted to travel down the road between any two junctions, if and only if the lights at both junctions are the same color at the moment of departing from one junction for the other. If a vehicle arrives at a junction just at the moment the lights switch it must consider the new colors of lights. Vehicles are allowed to wait at the junctions. You are given the city map which shows:
sample input |
sample output |
1 4 4 5 B 2 16 99 P 6 32 13 P 2 87 4 P 38 96 49 1 2 4 1 3 40 2 3 75 2 4 76 3 4 77 |
127 1 2 4 |
题意:图,无自交,无向,在每个时间每个节点有一个信号灯,可能是绿色或者紫色,信号灯变化规律:蓝色持续一段时间接着是紫色,允许在信号灯同样颜色的时候离开一个节点通过路到达另一个节点,到达瞬间颜色可以不一样,如果到达瞬间颜色改变,按照新颜色计算,允许任意点停留,
你能得到的状态:
1 所有路径花费时间
2 每个节点灯的持续周期
3 每个节点灯的初始颜色和还剩多长时间第一次变颜色
思路:注意到这道题每个节点通向另一个节点耗时是容易得出的,而且过程有意义的只有最早到节点的时间,知道源点,到达点求最短路,最短路算法就可以了
注意状态转化,主要是考细心
实际用时:1h38min
#include <cstdio> #include <cstring> #include <queue> using namespace std; typedef long long ll; const ll inf=0x7ffffffffff; const int maxn=305; const int maxm=50000; int n,m; ll dis[maxn];//最小距离(时间) int first[maxn];//邻接表 int nxt[maxm]; int to[maxm]; int cost[maxm]; int color[maxn];//初始颜色 int wait[maxn];//第一次变化时间 int time[maxn][2];//等待颜色 int pre[maxn];//路径回溯,前驱节点 queue<int >que; int sups,supe; char buff[3];//接收颜色用 int heap[maxn],len; void dfs(int s){//路径回溯 if(s==sups){ len=0; heap[len++]=s; return ; } dfs(pre[s]); heap[len++]=s; } int calcolor(int ttime,int s){//计算当前颜色 if(ttime<wait[s])return color[s]; ttime-=wait[s]; int c=color[s]^1; ttime-=((int)ttime/(time[s][0]+time[s][1]))*(time[s][0]+time[s][1]); if(ttime<time[s][c])return c; return color[s]; } int caltime(int ttime,int s){//计算变化颜色时间 if(ttime<wait[s])return wait[s]-ttime; ttime-=wait[s]; int c=color[s]^1; ttime-=((int)ttime/(time[s][0]+time[s][1]))*(time[s][0]+time[s][1]); if(ttime<time[s][c])return time[s][c]-ttime; return time[s][0]+time[s][1]-ttime; } void addedge(int f,int t,int c,int ind){ nxt[ind*2]=first[f]; cost[ind*2]=c; to[ind*2]=t; first[f]=ind*2; nxt[ind*2+1]=first[t]; cost[ind*2+1]=c; to[ind*2+1]=f; first[t]=ind*2+1; } void spfa(){ fill(dis,dis+n+1,inf); que.push(sups); dis[sups]=0; while(!que.empty()){ int s=que.front();que.pop(); int scolor=calcolor(dis[s],s); for(int p=first[s];p!=-1;p=nxt[p]){ int tto=to[p]; int tcolor=calcolor(dis[s],tto); if(scolor==tcolor){ if(dis[tto]>dis[s]+cost[p]){//颜色相同可以直接走 dis[tto]=dis[s]+cost[p]; pre[tto]=s; que.push(tto); } } else { int stime=caltime(dis[s],s); int ttime=caltime(dis[s],tto); if(stime==ttime&&time[s][scolor^1]==time[tto][tcolor^1]&&time[s][scolor]==time[tto][tcolor])continue;//这两个节点同步变化,永远走不了 if(stime==ttime){//如果变化周期不一样而现在等待时间一样就多等一周期 stime+=time[s][scolor^1]; ttime+=time[tto][tcolor^1]; } if(stime==ttime){//再多等一周期 stime+=time[s][scolor]; ttime+=time[tto][tcolor]; } if(dis[tto]>dis[s]+min(stime,ttime)+cost[p]){//更新 dis[tto]=dis[s]+min(stime,ttime)+cost[p]; pre[tto]=s; que.push(tto); } } } } } int main(){ while(scanf("%d%d",&sups,&supe)==2){ sups--;supe--; memset(first,-1,sizeof(first)); scanf("%d%d",&n,&m); for (int i=0;i<n;i++){ scanf("%s%d%d%d",buff,wait+i,time[i],time[i]+1); if(buff[0]=='B')color[i]=0; else color[i]=1; } for(int i=0;i<m;i++){ int f,t,c; scanf("%d%d%d",&f,&t,&c); f--;t--; addedge(f,t,c,i); } spfa(); if(dis[supe]==inf)puts("0"); else { printf("%I64d\n",dis[supe]); dfs(supe); for(int i=0;i<len;i++){ printf("%d%c",heap[i]+1,i==len-1?'\n':' '); } } } return 0; }