版权声明:本篇随笔版权归作者Etta(http://www.cnblogs.com/Etta/)所有,转载请保留原地址!
(1) 问题描述(probolem)
在d城里交通的安排不同寻常,城中有路口和路口之间的道路,在任意两个不同的路口之间之都有一条道路。从任何一个路口出发,不可能不经过其他路口直接回到该路口。在同一条路道上反正两个方向所需要的通过时间是相同的。在每个路口上只有一盏信号灯,信号灯的颜色在蓝色和紫色之间有规律的交替变化:蓝色有特定的持续时间,紫色也有特定的持续时间,再任意一条道路的两个路口之间,当且仅当这两个路口的信号灯在同一时刻颜色相同时,车辆才被允许实力一个路口驶向另一个路口。如果车辆到达一个路口时,该路口的信号灯正在切换,那么车辆必须组收信号灯的信号。车辆可以在路口等待。你拿到城市地图会显示出以下信息:
所有道路的通过时间(整数)
每一个路口上信号灯两种颜色信号各自的持续时间(整数)
每一个路口的信号灯的初始颜色及其发生变化之前的保持时间
你的任务是找出一条路径,使得车辆在交通开始时,用最短的时间,从指定的出发路口到达到指定的目的路口。假设有超过这一条这样的路径,你只需找出一条即可。
(2) 假设条件(assumptions)
2<=n<=300,这里n是路口的数量,路口用数字1至n标号。
1<=m<=14,000,这里m是道路的数量。
1<=<=100,这里lij是从路口i到路口j所需要的时间。
1 £ tic £ 100,这里tic是路口i的信号灯显示颜色c的持续时间。下标c为B,或P,分别代表蓝色和紫色。
1 £ ric £ tic这里ric是路口i信号灯初始颜色c的保持时间。
(3) 输入(input)
输入是名为lights.inp的正式文件(text file).
第一行保包含两个数:出发路口和目的路口的标号
第二行业包含两个数:N,M.
以下N行包行N个路口的信息,输入文件的第(I+2)行是关于路口I的信息:其中Ci或是B,或是P,表示路口的信号灯的初始颜色;ric是Ci颜色的保持时间;tIb是蓝色的持续时间,tiP是紫颜色的持续时间。最后m行包含m条道路的信息,每一行有三个数:i, j, lij分别是该道路所连接的两个路口的标号及车辆通过时间。
(4) 输出(output)
输出文件必须是名为lights.out的正文文件(text file)
如果所搜索的路径存在,则:
第一行包含从出发路口经最捷路径到目的路口所需要的时间。
第二行包含你所发现的最捷路径所经过路口的标号序列,你必须按通过的顺序输出路口的标号。因此,该行的第一个数应是出发路口的标号,而最后一个数则应是目的路口的标号。
如果所搜索的路径不存在,则:
输出文件只有一行,该行知包含一个整数0
(5) 例子(example)
lights.in:
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
lights.out:
127
1 2 4
评分
你的程序可以运行2秒
你的输出入正确,则得满分,否则的零分。
一. 分析问题
题目很长,可是不要被吓到,实质就是最短路问题加限制条件,第一反应是SPFA+队列。
二.解决问题
由于通过每一条路的时间是确定的,我们只需要算出从路口a到达路口b的等待时间w[a,b]+dis[a] +len[a,b]与dis[b]在SPFAZ中比较更新就好了。自己第一遍写的时候由于分类讨论不全面以及取等号的情况太纠结写得脑袋要炸了,读了别人的程序发现有一种更简明清晰的思路。
- Tmp=Calc(a,b,dis[a],1)//计算从a到b的时间w[a,b]+dis[a],理解为时刻也许更加形象
- color(a,time,&ca,&ta)
- color(b,time,&cb,&tb) //计算b在time此刻的颜色cb与变为下一个颜色所需时间tb
- if(ca==cb)return time;
- if(ta==tb)又分两种情况:1.未循环完全2.a不可能到达b
- if(ta!=tb)return min(ta,tb);
tips:
1.SPFA+邻接表省时间复杂度
2.用队列queue<>是一件很美妙的事情
三.代码实现
1 #include<cstdio> 2 #include<queue> 3 #include<iostream> 4 #include<cstring> 5 using namespace std; 6 7 const int MA=305,M=14000*2+10,inf=4e8; 8 struct edge{ 9 int to,nxt,len; 10 }e[M]; 11 int n,m,sum,st,en; 12 int i,j,h,tmp,x,y,z; 13 int c[MA],ex[MA],head[MA],dt[MA]; 14 int t[MA][2],dis[MA],pre[MA]; 15 char ch; 16 queue<int>q; 17 18 void build(int a,int b,int c) 19 { 20 ++sum; 21 e[sum].to=b; 22 e[sum].len=c; 23 e[sum].nxt=head[a]; 24 head[a]=sum; 25 } 26 27 void color(int x,int tx,int &cx,int &tt) 28 { 29 if(tx<dt[x]){cx=c[x];tt=dt[x];return;} 30 int g=(tx-dt[x])%(t[x][0]+t[x][1]); 31 if(c[x]==0) 32 { 33 if(g<t[x][1]) 34 {cx=1;tt=tx+t[x][1]-g;return;} 35 else 36 {cx=0;tt=tx+t[x][1]+t[x][0]-g;return;} 37 } 38 else 39 if(c[x]==1) 40 { 41 if(g<t[x][0]) 42 {cx=0;tt=tx+t[x][0]-g;return;} 43 else 44 {cx=1;tt=tx+t[x][1]+t[x][0]-g;return;} 45 } 46 } 47 48 int calc(int a,int b,int time,int sp) 49 { 50 int ta,tb,ca,cb; 51 color(a,time,ca,ta); 52 color(b,time,cb,tb); 53 if(ca==cb)return time; 54 if(ta==tb) 55 { 56 if(ta<=dt[a]||ta<=dt[b])calc(a,b,ta,1); 57 else return inf; 58 } 59 else 60 return min(ta,tb); 61 } 62 63 void print(int x) 64 { 65 if(pre[x])print(pre[x]); 66 printf("%d ",x); 67 } 68 69 int main() 70 { 71 scanf("%d%d%d%d ",&st,&en,&n,&m); 72 for(i=1;i<=n;++i) 73 { 74 scanf("%c%d%d%d ",&ch,&dt[i],&t[i][0],&t[i][1]); 75 if(ch=='B')c[i]=0;else c[i]=1; 76 } 77 for(i=1;i<=m;++i) 78 { 79 scanf("%d%d%d",&x,&y,&z); 80 build(x,y,z); 81 build(y,x,z); 82 } 83 84 for(i=1;i<=n;++i)dis[i]=inf; 85 dis[st]=0; 86 q.push(st); 87 while(!q.empty()) 88 { 89 h=q.front(); 90 q.pop(); 91 ex[h]=0; 92 for(i=head[h];i;i=e[i].nxt) 93 { 94 tmp=calc(h,e[i].to,dis[h],0); 95 if(tmp+e[i].len<dis[e[i].to]) 96 { 97 dis[e[i].to]=tmp+e[i].len; 98 pre[e[i].to]=h; 99 if(!ex[e[i].to]) 100 { 101 ex[e[i].to]=1; 102 q.push(e[i].to); 103 } 104 } 105 } 106 } 107 if(dis[en]!=inf) 108 { 109 printf("%d ",dis[en]); 110 print(en); 111 } 112 else printf("0 "); 113 return 0; 114 }
——Etta