POJ1158 城市交通Traffic lights IOI 1999 (最短路)
(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.inp lights.out:
|
|||
|
|||
解题报告
这个题构建最短路模型比较恶心。首先,在读入边的时候判断那条路永远不可能走,即灯变化的周期互相错开。之后,在最短路判断时要判断颜色是否一样,如果一样,就直接松弛,否者就计算至少要多久才会颜色一样。再判断是否可以松弛。
#include<bits/stdc++.h> #define Pair pair<int,int> #define MAXN 400+10 #define MAXM 40000+1 using namespace std; int n,m,num,head[MAXN],s,t,pre[MAXN],dis[MAXN],v[MAXM]; int bian[MAXM],ans[MAXN]; struct Edge{ int dis,next,to,exi,from; }edge[MAXM]; struct Crossing{ int co,tc,tp,tb; }c[MAXN]; void add(int from,int to,int dis) { edge[++num].next=head[from]; edge[num].to=to; edge[num].dis=dis; edge[num].from=from; head[from]=num; edge[num].exi=1; } int color(int x,int t) { int q=t-c[x].tc,r=q%(c[x].tp+c[x].tb); if(q<0) return c[x].co; if(c[x].co==1) { if(r<c[x].tp) return 2; else if(r>=c[x].tp) return 1; }else if(c[x].co==2) { if(r<c[x].tb) return 1; else if(r>=c[x].tb) return 2; } } void dij() { memset(dis,0,sizeof(dis)); memset(pre,0,sizeof(pre)); memset(v,0,sizeof(v)); priority_queue<Pair,vector<Pair>,greater<Pair> > h; for(int i=1;i<=n;i++) dis[i]=99999999; dis[s]=0; h.push(Pair(dis[s],s)); while(h.size()>0) { int k=h.top().second;h.pop(); if(v[k]) continue; v[k]=1; for(int i=head[k];i;i=edge[i].next) if(dis[k]+edge[i].dis<dis[edge[i].to]) { int d1=dis[edge[i].to],d2=0,dd=dis[edge[i].to]-dis[k],flag=0; int x=edge[i].to,y=edge[i].from; if(color(edge[i].to,dis[k])==color(edge[i].from,dis[k])) d2=dis[k]+edge[i].dis,flag=1; else for(int j=dis[k];j<=dis[edge[i].to];j++) { if(color(edge[i].to,j)==color(edge[i].from,j)) {d2=j+edge[i].dis;flag=1;break;} } if(flag==1&&d2<dis[edge[i].to]) { dis[edge[i].to]=d2; pre[edge[i].to]=i; h.push(Pair(d2,edge[i].to)); } } } } int main() { scanf("%d%d%d%d",&s,&t,&n,&m); for(int i=1;i<=n;i++) { char k[10]; scanf("%s%d%d%d",k,&c[i].tc,&c[i].tb,&c[i].tp); if(k[0]=='B') c[i].co=1; else if(k[0]=='P') c[i].co=2; } for(int i=1;i<=m;i++) { int x,y,z,e=0; scanf("%d%d%d",&x,&y,&z); if(c[x].tp==c[y].tb&&c[y].tp==c[x].tb) { if(c[x].tc==c[y].tc&&c[x].co!=c[y].co) e=1; else if(c[x].tc!=c[y].tc&&abs(c[x].tc-c[y].tc)%(c[x].tp+c[x].tb)==0) e=1; else if(c[x].tc==c[y].tc&&abs(c[x].tc-c[y].tc)%(c[x].tp+c[x].tb)==c[x].tb) e=1; else if(c[x].tc==c[y].tc&&abs(c[x].tc-c[y].tc)%(c[x].tp+c[x].tb)==c[x].tp) e=1; } if(!e) add(x,y,z), add(y,x,z); } dij(); if(dis[t]==99999999) {printf("0 ");return 0;} printf("%d ",dis[t]); for(int i=pre[t];i;i=pre[edge[i].from]) ans[++ans[0]]=edge[i].from; for(int i=ans[0];i>=1;i--) { printf("%d ",ans[i]); }printf("%d ",t); return 0; }