GESP2024年6月认证C++八级( 第三部分编程题(2)空间跳跃)

参考程序:

#include <cstdio>
#include <vector>
#include <queue>
#include <utility>
#include <cstring>
using namespace std;

// 定义一个结构体,用于 Dijkstra 优先队列中的节点
struct Node {
    int v, w; // v 表示图中的节点编号,w 表示当前从源点到 v 的最短距离
    bool operator < (const Node &b) const {
        // C++ 优先队列默认是大顶堆,这里重载为距离小的优先出队
        return w > b.w;
    }
};

// 假设最多 n 个挡板,我们编号为 1..n
const int MAXN = 10010;  // 挡板数量上限(可根据题目数据范围调整)
const int INF = 2000000000;

// 图的邻接表表示,每个节点存储 (目标节点, 权值) 对
vector<pair<int,int>> G[MAXN*2]; // 每个挡板有两个端点,编号方案见下

// 存储挡板数据
int l[MAXN], r[MAXN], h[MAXN]; // l[i], r[i] 为挡板 i 的左右横坐标,h[i] 为高度
int n, s, t; // n 挡板个数,s 起点挡板编号,t 目标挡板编号

// 将挡板编号转换为节点编号:例如取左端点编号 2*i,右端点编号 2*i+1
inline int LL(int x) { return 2*x; }
inline int RR(int x) { return 2*x+1; }

// Dijkstra 算法求单源最短路
int dis[MAXN*2];
bool vis[MAXN*2];
void Dijkstra(int src) {
    // 初始化距离为无穷大,标记都为未访问
    for(int i = 0; i < 2*n+2; i++) {
        dis[i] = INF;
        vis[i] = false;
    }
    // 源点距离置 0,入队
    dis[src] = 0;
    priority_queue<Node> pq;
    pq.push({src, 0});
    
    while(!pq.empty()) {
        Node cur = pq.top(); pq.pop();
        int u = cur.v;
        if(vis[u]) continue; // 如果已访问,跳过
        vis[u] = true;
        // 遍历所有从 u 出发的边
        for(auto &edge : G[u]) {
            int v = edge.first;
            int w = edge.second;
            if(!vis[v] && dis[v] > dis[u] + w) {
                dis[v] = dis[u] + w; // 松弛
                pq.push({v, dis[v]});
            }
        }
    }
}

int main(){
    // 读入挡板数量和起点、终点挡板编号
    scanf("%d %d %d", &n, &s, &t);
    // 读入每个挡板的左右坐标和高度
    for(int i = 1; i <= n; i++){
        scanf("%d %d %d", &l[i], &r[i], &h[i]);
        // 添加挡板 i 水平移动的双向边:左端到右端,权值为挡板长度
        G[LL(i)].push_back({RR(i), r[i] - l[i]}); 
        G[RR(i)].push_back({LL(i), r[i] - l[i]});
    }
    
    // 以下构造竖直掉落的边,采用辅助节点思路或直接加边思路任选其一
    // 这里以直接连边(两条边)为例:
    // 对于每个挡板 i 的左端点和右端点,找到其下方第一个挡板 j
    // 可以用两重循环暴力检查(效率 O(n^2)),寻找最低高度却高于 i 的挡板
    // 或者按照高度排序后逐一处理。此处示意逻辑:
    for(int i = 1; i <= n; i++){
        // 初始化记录,第一个落点挡板索引
        int dropL = 0, dropR = 0;
        for(int j = 1; j <= n; j++){
            if(h[j] < h[i]) { // 下方的挡板
                // 左端点下落:如果挡板 j 横跨了 i 的左端点位置
                if(l[i] >= l[j] && l[i] <= r[j]) {
                    // 取最近的挡板(高度最大的)
                    if(dropL == 0 || h[j] > h[dropL]) dropL = j;
                }
                // 右端点下落:如果挡板 j 横跨了 i 的右端点位置
                if(r[i] >= l[j] && r[i] <= r[j]) {
                    if(dropR == 0 || h[j] > h[dropR]) dropR = j;
                }
            }
        }
        // 如果找到了下方挡板,则添加掉落边
        if(dropL != 0) {
            int dh = h[i] - h[dropL]; // 竖直高度差
            // 从 i 的左端点掉落到 dropL 左端点、右端点
            G[LL(i)].push_back({LL(dropL), dh + (l[i] - l[dropL])});
            G[LL(i)].push_back({RR(dropL), dh + (l[dropL] + (r[dropL]-l[dropL]) - l[i])});
        }
        if(dropR != 0) {
            int dh = h[i] - h[dropR];
            // 从 i 的右端点掉落到 dropR 左端点、右端点
            G[RR(i)].push_back({LL(dropR), dh + (r[i] - l[dropR])});
            G[RR(i)].push_back({RR(dropR), dh + (r[dropR] - r[i])});
        }
    }
    
    // 求解最短路径。源点可以取 s 挡板的任意一端(比如左端 LL(s))
    Dijkstra(LL(s));
    
    // 计算答案:目标挡板 t 两端点的距离,以及可能的下落方式
    int ans = INF;
    // 直接到达目标挡板左/右端点
    ans = min(ans, dis[LL(t)]);
    ans = min(ans, dis[RR(t)]);
    // 如果允许从上方掉落到目标挡板(假设提前在循环中记录了落在 t 上的端点)
    // 也可以遍历所有节点,判断它们是否落到 t 上,并更新距离
    // 例如,我们可在上面循环中记录一组 “dropable” 节点,此处略写:
    // for(int u : dropable_to_t) ans = min(ans, dis[u] + (h[u/2] - h[t]));
    
    // 输出结果
    if(ans >= INF) {
        // 不可达,输出 -1
        printf("-1\n");
    } else {
        printf("%d\n", ans);
    }
    return 0;
}

很抱歉,我无法提供GESPP 20249月认证C++ 3编程题2的具体内容,因为我没有访问这些认证考试内容的权限。不过,我可以为你介绍一下C++编程中常见的一些高概念和问题类型,这些内容可能对你准备考试有所帮助。 ### C++ 编程高概念 1. **模板编程**: 模板是C++中实现泛型编程的一种方式。通过模板,可以编写与类型无关的代码,从而提高代码的复用性和灵活性。 ```cpp template <typename T> T add(T a, T b) { return a + b; } ``` 2. **STL(标准模板库)**: STL是C++标准库的一部分,提供了许多常用的数据结构和算法,如向量(vector)、列表(list)、映射(map)、集合(set)等。 ```cpp #include <vector> #include <algorithm> std::vector<int> vec = {1, 2, 3, 4, 5}; std::sort(vec.begin(), vec.end()); ``` 3. **多线程编程**: C++11引入了多线程支持,使得编写并发程序变得更加容易。 ```cpp #include <thread> void threadFunction() { // 线程执行的代码 } int main() { std::thread t(threadFunction); t.join(); return 0; } ``` 4. **智能指针**: 智能指针用于管理动态分配的内存,避免内存泄漏。 ```cpp #include <memory> std::unique_ptr<int> ptr(new int(5)); ``` ### 常见编程题类型 1. **数据结构实现**: 实现常见的数据结构,如链表、栈、队列、树等。 2. **算法实现**: 实现常见的算法,如排序算法、搜索算法、图算法等。 3. **问题解决**: 解决一些经典的问题,如最短路径问题、最小生成树问题、背包问题等。 4. **系统设计**: 设计一些简单的系统,如文本编辑器、简单的数据库、文件系统等。 如果你有具体的题目或概念需要了解,可以提供更多信息,我会尽力帮助你。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

汉克老师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值