sgu 103 Traffic Lights 解题报告及测试数据
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了。
以下是代码:
#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