103. Traffic Lights
Time limit per test: 0.25 second(s)
Memory limit: 4096 kilobytes
题解:
1、其实就是求两点间的最短路,不过加了交通灯的限制,使得两点间的所需时间并不只是由路程决定。
2、只有一条路两个端点的交通灯颜色相同时,该路才可以通过。但是这有一种情况,当两个交通灯处于不同颜色时,经过t时间,交通灯又恰好处于不同颜色,由于最初有一个颜色预变时间riC以及蓝色tiB、紫色周期tiP ,那么就需要计算交通灯变化时间的函数递归两次(函数执行三次),如果递归两次后还处于不同颜色,那么可以断定该交通灯蓝、紫色周期相反,不能通过。例如B 32 32 13和P 32 96 49 经过32s后变成P 13 32 13 和B 96 96 49(紫色变为蓝色后,将过tiB时间即96变为紫色),那么很显然,此时再过13s即可变为相同颜色。那么这两点所需等待交通灯时间为13+32=45s。一开始只都递归了一次,在test 6的时候挂了,所以计算等待函数,应递归两次。
3、最短路算法,dijkstra算法的复杂度为O(N^2),最后提交的结果是用时31ms。当然求最短路,dfs也是可以的,但是经过尝试,dfs在test 2 就TLE了。
以下是代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
|
#include <cstdio>
#include <iostream>
#include <cstring>
#include <climits>
#include <cstdlib>
using
namespace std;
int
st,ed;
int
N,M;
int
c[2][2]; //0 b,1 p;
int
a[310][310]; // 记录输入的无向图
int
Min=INT_MAX; // 最大值
struct
Light{ // 记录输入的交通灯的信息
int
c, t,b,p; // c输入的颜色,t变换时间,b,p周期
}L[310];
void
input(){ // 输入
int
t1,t2;
char
str[3];
scanf
(
"%d%d%d%d"
,&st,&ed,&N,&M);
for
(
int
i=1;i<=N;i++){
scanf
(
"%s%d%d%d"
,str,&L[i].t,&L[i].b,&L[i].p);
L[i].c= str[0] ==
'B'
? 0 :1;
}
for
(
int
i=1;i<=N;i++)
for
(
int
j=1;j<=N;j++)
if
(i!=j)a[i][j]=Min;
for
(
int
i=1;i<=M;i++){
scanf
(
"%d%d"
,&t1,&t2);
scanf
(
"%d"
,&a[t1][t2]);
a[t2][t1]=a[t1][t2];
}
}
void
calnow( int v, int pre, int k){ //计算第v个节点在过了pre时间后的颜色
if
(pre<L[v].t){
c[k][0] = L[v].c;
c[k][1] = L[v].t-pre;
return
;
}
int
mo = (pre - L[v].t)%(L[v].b+L[v].p);
switch
(L[v].c){
case
0 :
if
(mo < L[v].p){
c[k][0]=1;c[k][1]=L[v].p - mo;
}
else
{
c[k][0]=0;c[k][1]=L[v].b - (mo - L[v].p);
}
break
;
case
1 :
if
(mo < L[v].b){
c[k][0]=0;c[k][1]=L[v].b - mo;
}
else
{
c[k][0]=1;c[k][1]=L[v].p - (mo - L[v].b);
}
break
;
}
}
int
caldelay( int v, int u, int pre, int f){ // 计算如果走v—u需要多长时间
calnow(v,pre,0);
calnow(u,pre,1);
if
(c[0][0] == c[1][0])
return
0;
int
t1 = c[0][1],t2=c[1][1];
if
(t1 == t2){
if
(f==2)
return
-1; else {
int
t = caldelay(v,u,pre+t1,f+1); //递归两次,才能确定能否通行。
if
(t==-1)
return
-1;
return
t+t1;
}
}
return
t1<t2 ? t1:t2;
}
void
dijkstra() // 狄杰斯特拉算法,求最短路
{
int
v=st;
int
d[310],pr[310],vis[310];
memset
(vis,0,
sizeof
(vis));
memset
(pr,0,
sizeof
(pr));
for
(
int
i=0;i<310;i++)d[i]=Min;
for
(
int
i=1;i<=N;i++)
if
(a[v][i]<Min){
d[i]=a[v][i]+caldelay(v,i,0,0);
pr[i]= v;
}
else
{ d[i]=Min;pr[i]=0;}
vis[v]=1;pr[v]=0;
for
(
int
i=1;i<=N;i++){
int
k=0,m=Min;
for
(
int
j=1;j<=N;j++)
if
(!vis[j] && d[j]< m)m = d[k=j];
if
(k==0)
break
;
vis[k]=1;
for
(
int
j=1;j<=N;j++)
if
(k!=j && a[k][j]!=Min){
int
t = caldelay(k,j,d[k],0);
if
(t==-1)
continue
;
if
(d[j]>d[k]+t+a[k][j]){
d[j] = d[k]+t+a[k][j];
pr[j]=k;
}
}
}
if
(st==ed)
printf
(
"0\n%d\n"
,st);
else
if (d[ed]==Min) printf ( "0\n" );
else
{
printf
(
"%d\n"
,d[ed]);
int
t =ed,path[310],k=0;
while
(pr[t]){ path[++k]=pr[t];t =pr[t];}
path[0]=ed;
for
(
int
i=k;i>=0;i--)
printf
(
"%d "
,path[i]);
printf
(
"\n"
);
}
}
int
main(){
//freopen("1.in","r",stdin);
input();
dijkstra();
}
|
以下是测试数据:
sample input
10 2
17 2
B 42 5 96
B 47 51 60
B 49 28 70
B 71 77 17
P 95 97 59
B 5 56 99
B 82 56 74
P 97 60 15
P 78 32 54
B 3 20 55
B 84 8 46
P 93 32 64
B 25 11 99
B 73 33 15
B 59 58 70
P 85 61 61
P 53 13 43
6 12 17
15 12 75
4 4
13 11
P 79 49 75
B 87 71 22
B 11 79 30
P 91 1 72
B 50 59 84
B 88 72 41
B 85 21 47
B 66 11 100
B 39 21 28
B 42 59 42
P 4 47 2
B 41 36 48
P 97 60 25
11 3 38
10 10 57
7 6 86
5 9 69
7 9 17
5 9 77
4 10 13
6 3 79
2 8 78
3 12 90
13 9 37
4 5
5 20
P 35 52 3
B 10 82 91
B 29 81 35
P 85 62 64
B 87 27 12
3 5 39
3 4 98
5 3 19
4 2 4
5 1 36
4 1 94
4 2 12
3 4 41
5 2 90
4 2 2
3 1 71
3 1 33
5 1 94
1 5 67
1 4 65
4 1 54
4 5 16
3 3 22
1 2 19
2 5 76
1 3
4 17
B 73 40 10
P 38 5 50
B 46 64 69
P 93 88 94
1 3 91
3 4 72
2 3 14
4 3 46
3 2 5
2 2 52
2 3 26
1 3 93
1 1 75
4 4 84
4 1 39
2 3 63
3 2 10
4 1 70
1 1 71
2 4 75
1 2 34
sample output
0
0
4
71
4 2 1 5
77
1 2 3