sgu103: Traffic Lights

翻译:

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

1 通过所有公路需要的时间(整数)
2 每个路口交通灯两种颜色的持续时间(整数)
3 每个路口交通灯的初始颜色以及初始颜色的持续时间(整数).
你的任务是找到一条从起点到终点的最快路径,当有多条这样的路径存在时,你只需输出任意一条即可。

分析:
最短路

#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;

#define inc(x) (x = (x+1) % MOD)

const int maxn = 306;
const int maxm = 28006;
const int MOD = maxm;
const int oo = 0x3f3f3f3f;
inline int read()
{
    int x = 0, f = 1, t = getchar();
    while(t < '0' || t > '9') {
        if(t == '-') f = -1;
        t = getchar();
    }
    while(t >= '0' && t <= '9') {
        x = (x << 1) + (x << 3) + t - '0';
        t = getchar();
    }
    return x * f;
}
inline int min(int a, int b) { return a < b ? a : b; }

struct Edge
{
    int u, v, w;
    Edge(int u = 0, int v = 0, int w = 0): u(u), v(v), w(w) {}
};

int n, m, s, t;
int C[maxn], R[maxn], T[maxn][2], S[maxn];
int head[maxn];
int next[maxm];
Edge edge[maxm];
int fa[maxn];

void addedge(int a, int b, int c)
{
    edge[++m] = Edge(a, b, c);
    next[m] = head[a], head[a] = m;
}
void init()
{
    memset(head, -1, sizeof(head));
    s = read(), t = read(), n = read();
    int mm = read(), a, b, c;
    for(int i = 1; i <= n; ++i) {
        C[i] = (getchar() == 'B' ? 0 : 1);
        R[i] = read(), T[i][0] = read(), T[i][1] = read();
        S[i] = T[i][0] + T[i][1];
    }
    for(int i = 1; i <= mm; ++i) {
        a = read(), b = read(), c = read();
        addedge(a, b, c);
        addedge(b, a, c);
    }
}
int color(int u, int t, int &r)
{
    if(t < R[u]) {
        r = R[u] - t;
        return C[u];
    }
    t = (t - R[u]) % S[u];
    if(t >= T[u][C[u]^1]) {
        r = S[u] - t;
        return C[u];
    }
    else {
        r = T[u][C[u]^1] - t;
        return C[u]^1;
    }
}
int calc(int u, int v, int t)
{
    int ru, rv, cu = color(u, t, ru), cv = color(v, t, rv);
    if(cu == cv) return 0;
    if(ru != rv) return min(ru, rv);
    if(T[u][!cu] != T[v][!cv])
        return ru + min(T[u][!cu], T[v][!cv]);
    return oo;
}
int spfa()
{
    static int que[maxm] = {s}, h = 0, r = 1;
    static int dis[maxn], inq[maxn] = {0};
    memset(dis, oo, sizeof(dis)), dis[s] = 0;
    while(h != r) {
        int x = que[h];
        inc(h);
        inq[x] = 0;
        for(int i = head[x]; i != -1; i = next[i]) {
            Edge &e = edge[i];
            int cost = calc(x, e.v, dis[x]);
            if(cost == oo) continue;
            if(dis[e.v] > dis[x] + e.w + cost) {
                dis[e.v] = dis[x] + e.w + cost;
                fa[e.v] = x;
                if(!inq[e.v]) {
                    que[r] = e.v;
                    inq[e.v] = 1;
                    inc(r);
                }
            }
        }
    }
    return dis[t];
}
void work()
{
    static int stack[maxn] = {0}, top = 0;
    int ans = spfa();
    if(ans < oo) {
        printf("%d\n", ans);
        for(int x = t; x != s; x = fa[x])
            stack[top++] = x;
        printf("%d", s);
        while(top--) printf(" %d", stack[top]);
    }
    else puts("0");
}
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout);
    #endif

    init();
    work();

    #ifndef ONLINE_JUDGE
    fclose(stdin);
    fclose(stdout);
    #endif
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值