蓝桥杯 交通信号 2022研究生组

问题:
在这里插入图片描述

Dijstra算法变形题,有向边分正行和逆行方向,注意逆行的绿灯时间是正行的红灯时间
这题的关键是理清从当前节点出发,到下一个节点是哪一时刻,理清这一点后,再跑Dijstra算法求最短路。
假设curr_t时刻到达u节点,到达邻居v的时刻为nei_t
无论是正行还是逆行,红绿灯的周期T = g + y + r + y,因此curr_t时刻红绿灯的状态等价于p=curr_t%T 时刻的状态
根据p(即红绿灯的状态)分类讨论:

1.走正行道,绿黄红黄顺序等红绿灯, g y r y :

①:p < g, 到达邻居的时间nei_t = curr_t + y,即当前时间加上到达邻居节点的时间y(也是黄灯时间)
②:p >= g, 到达邻居的时间nei_t = curr_t + (g + r + y + y - p) + y,(g + r + y + y - p)为等待绿灯的时间

2.走逆行道,红黄绿黄顺序等红绿灯, r y g y:

①:p < r + y,到达邻居的时间nei_t = curr_t + (r + y - p) + y,(r + y - p)是等绿灯的时间
②:p>=r+y && p < r + y + g, 到达邻居的时间nei_t = curr_t + y,无需等待绿灯
③:p>=r+y+g:到达邻居的时间nei_t = curr_t + (r + y + g + y - p + r + y) + y,
情况③比较特殊,需要等待当前周期结束(即r + y + g + y - p),再等下一个周期的红灯和黄灯(r + y)

#include <iostream>
#include <bits/stdc++.h>
#define ll long long int
using namespace std;
const int MAX = 100010;
struct Edge {
  // dir为true表示正行
  int to, ne, g, r, y;
  bool dir;
  Edge() {}
  Edge(int to, int ne, int g, int r, int y, bool dir) : to(to), ne(ne), g(g), r(r), y(y), dir(dir) {}
} e[3000000];

struct Node {
  int n;
  ll t;
  Node(int n, ll t) : n(n), t(t) {}
  bool operator < (const Node &n1) const {
    return t > n1.t;
  }
};

int cnt = 1;
int h[MAX] = {0};
void add(int u, int v, int g, int r, int y, bool dir) {
  e[cnt].ne = h[u];
  e[cnt].to = v;
  e[cnt].g = g;
  e[cnt].r = r;
  e[cnt].y = y;
  e[cnt].dir = dir;
  h[u] = cnt++;
}

int f[MAX];
int find(int x) {
  return x == f[x] ? f[x] : (f[x] = find(f[x]));
}

int main()
{
  // 请在此输入您的代码
  int n, m, src, tar;
  int u, v, g, r, d;
  cin >> n >> m >> src >> tar;
  ll t[MAX] = {0};
  for(int i = 0; i < MAX; i++) {
    f[i] = i;
    t[i] = 0x1fffffffffffffff;
  }
  for(int i = 0; i < m; i++) {
    scanf("%d %d %d %d %d", &u, &v, &g, &r, &d);
    add(u, v, g, r, d, true);
    // 逆行的绿灯时间是正行的红灯时间
    add(v, u, r, g, d, false);
    int fx = find(u);
    int fy = find(v);
    if(fx != fy) f[fx] = fy;
  }
  if(find(src) != find(tar)) {
    cout << -1;
    return 0;
  }

  priority_queue<Node, vector<Node>> pq;
  t[src] = 0;
  pq.push({src, 0});
  while(!pq.empty()) {
    int curr = pq.top().n;
    ll curr_t = pq.top().t;
    pq.pop();
    if(curr == tar) {
      cout << curr_t;
      return 0;
    }
    for(int edge = h[curr]; edge; edge = e[edge].ne) {
      bool dir = e[edge].dir;
      int to = e[edge].to;
      ll g = e[edge].g;
      ll r = e[edge].r;
      ll y = e[edge].y;
      ll nei_t;
      ll p = curr_t % (g + r + y + y);
      if(dir) {
        // 走正行道,绿黄红黄顺序等红绿灯, g  y  r  y
        nei_t = p < g ? (curr_t + y) : (curr_t + g + r + y + y - p + y);
      } else {
        // 走逆行道,红黄绿黄顺序等红绿灯      r  y  g  y
        if(p < r + y)          nei_t = curr_t + r + y - p + y;
        else if(p < r + y + g) nei_t = curr_t + y;
        else                   nei_t = curr_t + r + y + g + y - p + r + y + y;
      }
      if(nei_t < t[to]) {
        t[to] = nei_t;
        pq.push({to, nei_t});
      }
    }
  }
  return 0;
}

### 蓝桥杯 C++ 第十届 研究生 比赛资料 #### 关于蓝桥杯竞赛概述 蓝桥杯全国软件和信息技术专业人才大赛是一项面向全国高校在校大学生的科技活动,旨在推动软件开发技术的发展,促进软件专业技术人才培养。该赛事分为多个类别,其中包括针对不同教育层次的学生设置的不同别。 #### 十届研究生比赛特点 对于第十届蓝桥杯竞赛中的C++程序设计语言部分,在研究生级别比赛中通常会考察更深入的知识和技术能力。这类考试不仅测试基本编程技能,还包括算法分析、数据结构应用以及解决实际问题的能力等方面的内容[^1]。 #### 题目类型与难度 具体到第十届的比赛情况,题目涵盖了多种计算机科学的核心概念和技术挑战。例如,在单片机项目中涉及到串口通信的应用就是一个典型例子,这表明参赛者需要具备一定的硬件接口编程经验和理解。另外,在软件类别的试题解答方面,则强调了广度优先搜索(BFS)算法用于寻找最优路径的方法论,并通过特定的方向编码来确保解决方案既是最短也是字典序最小化的路线[^2]。 #### 参加此类竞赛建议准备事项 为了更好地应对这样的高水平竞争环境,学生应该注重以下几个方面的准备工作: - 加强基础理论学习,特别是那些经常出现在历年真题里的知识点; - 多做模拟练习,熟悉各种可能遇到的问题场景及其对应的高效求解策略; - 掌握常用的数据结构和经典算法实现细节,提高代码编写效率和质量; - 积累实战经验,参加校内外各类小型编程比赛作为热身训练。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值