SGU 103 解题手记
2007 解题报告 Popularity: 1%
给的图是一个动态的图,边权非负且在发生周期性的变化。要求两点之间的最短路。
考虑Dijstra还能不能用。Dijstra的过程是不断将距离源点最近的点加入集合S,直到目标点也被加入S。Dijstra要求随着路径上节点数目的增加,路径长度也相应增加,即不能出现负权边。他的贪心基于这样的考虑:若能尽早到达某个点,就尽早到达,尽早到达这个点时扩展出的经过这个点的路径,比较晚达到这个点时扩展出的经过这个点的路径短。这个题中,边权的变化是有规律的,我发现尽早到达的想法仍然正确。所以Dijstra可以用。
下面想想怎么求某一时刻的边权。边权有两个组成部分:一部分是通过这条道路需要的时间,另一部分是在路口等待的时间。给出时刻t,可以求得道路两端的灯的颜色。若颜色相同,则等待时间即为0;若颜色不同,则需等到某一个灯换颜色为止,特殊的,两个灯同时换了颜色,则需要再等某个灯换颜色,如果出现两个灯连续三次同时变换颜色,则这条道路永远无法通行:
设某时刻灯A为紫色,灯B为蓝色。第一次同时变色后,灯A为蓝色,灯B为紫色。而后两灯第二次同时变色,说明灯A的蓝色周期与灯B的紫色周期相等。第三次同时变色,说明灯A的紫色周期与灯B的蓝色周期相等。即,两灯颜色变换的总周期相同而相位相反,说明这条道路无法通行了。
程序中将用true代表blue,用false代表purple。
Submit 1: WA on 3。在处理连续三次同时变色则道路无法通行时出错。我定义在路口等待的时间为-1时表示无法通行,而我在递归处理连续三次同时变色时,居然写了这样的句子:
if (flag>3) return -1;
if (v1.t==v2.t) return waittime(time+v1.t,a,b,flag+1)+v1.t;
没有做特殊判断,直接用-1就加上v1.t,自然返回不了-1了。
Submit 2: WA on 3。把Prim的东西混入到Dijstra里了。Prim里有两个集合——树上集和非树上集,Dijstra里的两个集合是路径点集和非路径上点集。这两个集合的维护方式类似,但意义是不同的。
程序结构做了一番改变。
Submit 3: WA on 2。忘了图是无向的了。
Submit 4: WA on 2。Dijstra又写错了。
Submit 5: TLE on 5。很可能是iostream造成的。
Submit 6: AC。
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 114 115 116 117 118 119 120 121 122 | #include <cstdio> #include <algorithm> using namespace std; struct color { bool c; int t; }; struct vertex { int id,arrtime; vertex *pre; int tB,tP,rC; bool initC; vertex():arrtime(-1),pre(0){} color getcolor(int time); }; color vertex::getcolor(int time) { color r; if (time<rC) { r.c=initC; r.t=rC-time; } else if (!initC) ///if initC is purple { if (r.c=(time-rC)%(tB+tP)<tB) r.t=tB-(time-rC)%(tB+tP); else r.t=tB+tP-(time-rC)%(tB+tP); } else ///if blue { if (r.c=(time-rC)%(tB+tP)>=tP) r.t=tB+tP-(time-rC)%(tB+tP); else r.t=tP-(time-rC)%(tB+tP); } return r; } bool operator <(vertex &a,vertex &b) ///acturraly this is > { if (a.arrtime>=0 && b.arrtime>=0) return a.arrtime>b.arrtime; else return a.arrtime<0; } int time2go(int time,vertex &a,vertex &b,int flag) { if (flag>3) return -1; color v1=a.getcolor(time),v2=b.getcolor(time); if (v1.c==v2.c) return time; if (v1.t==v2.t) return time2go(time+v1.t,a,b,flag+1); return time+min(v1.t,v2.t); } int map[301][301]; vertex vertexes[301]; bool inpath[301]; void printpath(vertex *v) { if (v->pre) printpath(v->pre); printf("%d ",v->id); } void changevalue(int i,int value) { vertexes[i].arrtime=value; while (i>1) if (vertexes[i>>1]<vertexes[i]) { swap(vertexes[i],vertexes[i>>1]); i>>=1; } else break; } int main() { int source,dest,n,m; scanf("%d %d %d %d",&source,&dest,&n,&m); for (int i(1);i<=n;i++) { char str[10]; vertexes[i].id=i; scanf("%s %d %d %d",str,&vertexes[i].rC,&vertexes[i].tB,&vertexes[i].tP); vertexes[i].initC=(str[0]=='B'); } changevalue(source,0); for (int i(1);i<=m;i++) { int n1,n2,t; scanf("%d %d %d",&n1,&n2,&t); map[n1][n2]=t; map[n2][n1]=t; } inpath[source]=true; while (!inpath[dest]) { pop_heap(vertexes+1,vertexes+n+1); if (vertexes[n].arrtime<0) { printf("0\n"); return 0; } inpath[vertexes[n].id]=true; for (int i(1);i<n;i++) if (map[vertexes[n].id][vertexes[i].id]) { int t=time2go(vertexes[n].arrtime,vertexes[n],vertexes[i],1); if (t>=0 && (vertexes[i].arrtime<0 || t+map[vertexes[n].id][vertexes[i].id]<vertexes[i].arrtime)) { vertexes[i].pre=&vertexes[n]; changevalue(i,t+map[vertexes[n].id][vertexes[i].id]); } } n--; } for (int i=1;;i++) if (vertexes[i].id==dest) { dest=i; break; } printf("%d\n",vertexes[dest].arrtime); printpath(&vertexes[dest]); printf("\n"); return 0; } |
- http://www.briefdream.com/sgu-103/
- Tags:Dijstra, Eva, SGU, 动态图, 贪心
- (1)comments | leave a reply
- Trackback URI
June 22nd, 2007 at 18:19 pm
:em21: 感谢你的评论额,呵呵
Reply