时间: 0.50 second(s)

空间: 4096 kilobytes

输入: 标准输入

输出: 标准输出

Dingiville 城市的交通规则非常奇怪,城市公路通过路口相连,两个不同路口之间最多只有一条直达公路。公路的起止点不会是同一路口。在任意一条公路上顺不同方向走所需 时间相同。每一个路口都有交通灯,这些交通灯在某一时刻要么是蓝色,要么是紫色。同一个灯上2个颜色的维持时间受到定期调控,总是蓝色持续一段时间,紫色 持续一段时间。交通规则规定两个路口可以通车仅当公路两边交通灯的颜色相同(也就是说只要你在A城市看见A与B的交通灯颜色相同,那么你就可以走上A-B 这条路并到达B点)。交通工具可以在路口等候。现在你有这个城市的地图,包含:

• 通过所有公路需要的时间(整数)

• 每个路口交通灯两种颜色的持续时间(整数)

• 每个路口交通灯的初始颜色以及初始颜色的持续时间(整数).

你的任务是找到一条从起点到终点的最快路径,当有多条这样的路径存在时,你只需输出任意一条即可。

输入

第一行包含两个整数: 起点和终点的编号. 第二行包含两个整数: N, M. 接下来 N 行描述 N 个路口的情况.

第 (i+2) 行 是 i 号路口的信息: Ci, riC, tiB, tiP 。其中字符 Ci 要么是“B”代表蓝色,要么是“P”代表紫色,表示 i 的 起始颜色. riC, tiB, tiP 分别表示初始颜色,蓝色,紫色的持续时间, 1 ≤ tiC ≤ 100 . 1 ≤ riC ≤ tiC 。最后的 M 行表示关于 M 条公路的信息。包含: i, j, lij 。i 和 j 号路口被这条路连接. 2 ≤ N ≤ 300 表示路口数. 路口从 1 到 N 编号. 1 ≤ M ≤ 14000 公路从 1 到 M 编号. 1 ≤ lij ≤ 100 表示 lij 是通过i到j这条公路需要的时间。

输出

如果存在最短路径:

• 第一行输出最短时间。

• 第二行是一个对应第一行答案的路口编号表,从起点到终点输出路口编号,数字之间用空格隔开。

如果不存在:

• 输出“0”.

样例 输入

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

输出

127

1 2 4

{=======================}

分析:

很明显的一个最短路问题,但是比较麻烦的是距离的计算

如下图:

对于两个城市的信号灯的变化,可以在时间轴上画出,黑色部分是当前颜色剩余时间Ci,当Ci 等于0时,其实相当于进入了下一种颜色,并且Ci为下一种颜色的最大时间,即持续时间。

如果两个信号灯不是初始一样,就是在其中一个灯比另一个灯多变化1次后一样。如果两个信号灯总是同时变化,并且初始颜色不同的话,那么就是不能通过。

可以用两个函数,来实现计算,一个为afterT(u,T)得到在T时间后,u灯的颜色和当前颜色的剩余时间,

另一个为getT(u,v),得到为了从路口u到路口v最少需要的时间,这里在计算从u到v的时间时,要把u和v两个路口的时间轴的起点调到从起点到u的最短时间。

大概的框架就是SPFA加上 计算函数afterT()和getT();

下面要处理一些细节,让程序更加好写。

先来考虑,什么时候两个路口间的道路是不能通过的?

之前说过,如果两个信号灯总是同时变化,并且初始颜色不同的话,那么就是不能通过。那么就是说如果(u,v)间不能通过,一定满足Cu == Cv

并且满足BTu ==PT和 PTu ==BTv ,如果确定两个路口不能互相到达,我们直接删除两个路口间的边,方便计算getT()。

在处理了不能通过的情况下, getT(u,v)简单地枚举每次最近的变化就好了,最多2次,就可以得到等待时间waitT,而我们需要的返回值应该是

waitT+Edge[u][v];Edge[u][v]是通过连接(u,v)的路的时间。

伪代码在这:

int getT ( u,  v) {
u = afterT (u, 到达u的时间), v = afterT (v, 到达u的时间);
int m1 = u当前颜色剩余时间, m2 = 当前颜色剩余时间, waitT = 0;
while (u当前颜色 != v当前颜色) {
if (m1 < m2)
waitT += m1, u变颜色;
else if (m1 > m2)
waitT += m2, v变颜色;
else {
waitT += m1, u,v同时变颜色;
m1 = 当前颜色持续时间, m2 = 当前颜色持续时间;
}
}
return waitT + 通过(u,v)的时间;
}

至于afterT()就非常简单了,从前往后一个一个推就行了

参考代码:

#include <cstdio>
#include <queue>
using namespace std;
const int INF = 311;
struct data {
int sta, ti;
} f[INF];
queue<int> ql;
//dTi[i]记录从起点到i的最短时间,pr[v]指向上一个路口,tBP记录信号灯的持续时间
int Edge[INF][INF], tBP[INF][2], dTi[INF], pd[INF], pr[INF];
int n, m, S, A, x, y, z;
//计算T时间后p的颜色,和当前颜色的剩余时间
data afterT (int p, int t) {
data x = f[p];
while (t) {
if (t <= x.ti) {
x.ti -= t; t = 0;
}
else {
t -= x.ti; x.sta ^= 1;
x.ti = tBP[p][x.sta];
}
}
if (x.ti == 0) {
x.sta ^= 1;
x.ti = tBP[p][x.sta];
}
return x;
}
//计算从经过u到v的最少需要的时间
int getT (int u, int v) {
data uSt = afterT (u, dTi[u]), vSt = afterT (v, dTi[u]);
int m1 = uSt.ti, m2 = vSt.ti, waitT = 0;
while (uSt.sta != vSt.sta) {
if (m1 < m2)
waitT += m1, uSt.sta ^= 1;
else if (m1 > m2)
waitT += m2, vSt.sta ^= 1;
else {
waitT += m1, uSt.sta ^= 1, vSt.sta ^= 1;
m1 = tBP[u][uSt.sta], m2 = tBP[v][vSt.sta];
}
}
return waitT + Edge[u][v];
}
//最短路
void SPFA() {
dTi[S] = 0, pd[S] = 1, ql.push (S);
while (!ql.empty() ) {
int x = ql.front(), k;
ql.pop();
for (int i = 1; i <= n; i++) {
if (i == x || Edge[x][i] == 0) continue;
k = getT (x, i);
if (dTi[i] == 0 || dTi[x] + k < dTi[i]) {
dTi[i] = dTi[x] + k, pr[i] = x;
if (pd[i] == 0 && i != A) pd[i] = 1, ql.push (i);
}
}
pd[x] = 0;
}
}
//递归输出路径
void write (int x) {
if (x != S) write (pr[x]);
printf ("%d ", x);
}
int main() {
scanf ("%d%d", &S, &A);
scanf ("%d%d", &n, &m);
char ch = getchar();
for (int i = 1; i <= n; i++, getchar() ) {
scanf ("%c %d %d %d", &ch, &f[i].ti, &tBP[i][0], &tBP[i][1]);
if (ch == 'B') f[i].sta = 0;
else f[i].sta = 1;
if (f[i].ti == 0) { f[i].sta ^= 1; f[i].ti = tBP[i][f[i].sta];}
}
for (int i = 1; i <= m; i++) {
scanf ("%d%d%d", &x, &y, &z);
Edge[x][y] = Edge[y][x] = z;
}
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++) {
if (i == j || Edge[x][y] == 0) continue;
if (f[i].sta != f[j].sta && f[i].ti == f[j].ti &&
tBP[i][0] == tBP[j][1] && tBP[i][1] == tBP[j][0])
Edge[i][j] = Edge[j][i] = 0;
}
SPFA();
printf ("%d\n", dTi[A]);
if (dTi[A]) write (A);
return 0;
}

http://www.cnblogs.com/keam37/ keam所有 转载请注明出处

SGU 103.Traffic Lights(最短路)的更多相关文章

  1. sgu 103 Traffic Lights 解题报告及测试数据

    103. Traffic Lights Time limit per test: 0.25 second(s) Memory limit: 4096 kilobytes 题解: 1.其实就是求两点间的 ...

  2. SGU 103 Traffic Lights【最短路】

    题目链接: http://acm.hust.edu.cn/vjudge/problem/visitOriginUrl.action?id=16530 题意: 给定每个点最初的颜色,最初颜色持续时间,以 ...

  3. sgu 103 Traffic Lights

    这道题难得不是算法,而是处理. 题意就是让你求最短路,只有当两个点在某一秒颜色相同时,这条边才可以通行,输入首先给你 起点和终点, 然后给你 点数和边数, 接下来 n 行 初始颜色,初始颜色持续时间, ...

  4. 快速切题 sgu103. Traffic Lights 最短路 难度:1

    103. Traffic Lights Time limit per test: 0.25 second(s)Memory limit: 4096 kilobytes input: standardo ...

  5. POJ1158 城市交通Traffic lights IOI 1999 (最短路)

    POJ1158 城市交通Traffic lights IOI 1999 (最短路) (1) 问题描述(probolem) 在d城里交通的安排不同寻常,城中有路口和路口之间的道路,再任意两个不同的路口之 ...

  6. Traffic Lights

    Traffic Lights time limit per test 2 seconds memory limit per test 256 megabytes input standard inpu ...

  7. Traffic Lights - SGU 103(最短路)

    题目大意:有一个城市的路线图,有N个交叉点,每两个交叉点之间只有一条路,现在想从交点u去交点v,不过这个路的交通比较特别,每个路都有一个交通灯,灯有两种颜色,蓝色和紫色,例如一条路线在交点s,t之间, ...

  8. LightOJ 1074 Extended Traffic (最短路spfa+标记负环点)

    Extended Traffic 题目链接: http://acm.hust.edu.cn/vjudge/contest/122685#problem/O Description Dhaka city ...

  9. Codeforces 954D Fight Against Traffic(BFS 最短路)

    题目链接:Fight Against Traffic 题意:有n个点个m条双向边,现在给出两个点S和T并要增加一条边,问增加一条边且S和T之间距离不变短的情况有几种? 题解:首先dfs求一下S到其他点 ...

随机推荐

  1. 【转】XCode快捷键

    原文网址:http://www.cnblogs.com/yjmyzz/archive/2011/01/25/1944325.html 1. 文件 CMD + N: 新文件CMD + SHIFT + N ...

  2. JavaScript高级程序设计8.pdf

    基本包装类型 为了便于操作基本类型值,ECMAScript定义了3个特殊的引用类型Boolean,Number和String.这些类型与本章介绍的其他用类型相似,同时也具备与各自的基本类型相应的特殊行 ...

  3. CPP变量参数别名

    1,变量起"绰号"的操作称为引用(reference),"绰号"称为引用名,申明引用的语法格式; 变量数据类型 &引用名 = 已申明的变量名; 和C中的 ...

  4. Redis教程02——管道(Pipelining)

    请求/响应协议和RTT Redis是一个使用客户端/服务器模型(也被称作请求/响应协议)的TCP服务器. 这说明通常来讲一个一个请求的实现有以下步骤: 客户端发送请求到服务器,并从socket中以堵塞 ...

  5. LogMiner学习笔记

    本文是个实战,没有讲太多理论的东西,如需详细理解Oracle LogMiner,请移步:LogMiner详细讲解 首先介绍一下我的oracle环境: 第一步: 确定LogMiner已经安装. 安装Lo ...

  6. Parallel.Foreach的并发问题解决方法-比如爬虫WebClient

    场景五:线程局部变量 Parallel.ForEach 提供了一个线程局部变量的重载,定义如下: public static ParallelLoopResult ForEach<TSource ...

  7. sdut-2725-The Urge to Merge-状压DP

    把数组竖起来,从上往下走. 如果当前位置是竖着乘的,那么第一个点标记为1.否则标记为0. 样例最终的状态为: 0 0 1 0 1 0 1 0 0 0 0 0 #include<iostream& ...

  8. 【Android - 框架】之OkHttp的使用

    OkHttp是一个非常优秀的网络访问框架,当下非常火的Retrofit的底层就是使用OkHttp进行封装的.接下来介绍以下OkHttp的简单使用. 1.导入依赖 在Android Studio中,在M ...

  9. Android 仿PhotoShop调色板应用(二) 透明度绘制之AlphaPatternDrawable

    版权声明:本文为博主原创文章,未经博主允许不得转载. Android 仿PhotoShop调色板应用(二) 透明度绘制之AlphaPatternDrawable 这里讲一下如何实现PS调色板中的透明度 ...

  10. #IOS-navigation中左滑pop的三种方法

    IOS-navigation中左滑pop的三种方法 系统自带pop方法 如果我们没有对navigation中的back按钮进行自定义,我们可以直接使用系统自带的左滑pop方法.但是如果我们对back按 ...