1

GESP认证C++编程真题解析 | 202509 七级

欢迎大家订阅我的CSDN专栏算法题解:C++与Python实现
本专栏旨在帮助大家从基础到进阶 ,逐步提升编程能力,助力信息学竞赛备战!

专栏特色
1.经典算法练习:根据信息学竞赛大纲,精心挑选经典算法题目,提供清晰的代码实现与详细指导,帮助您夯实算法基础。
2.系统化学习路径:按照算法类别和难度分级,从基础到进阶,循序渐进,帮助您全面提升编程能力与算法思维。

适合人群:

  • 准备参加蓝桥杯、GESP、CSP-J、CSP-S等信息学竞赛的学生
  • 希望系统学习C++/Python编程的初学者
  • 想要提升算法与编程能力的编程爱好者

附上汇总帖:GESP认证C++编程真题解析 | 汇总


编程题

P14077 连通图

【题目来源】

洛谷:[P14077 GESP202509 七级] 连通图 - 洛谷

【题目描述】

给定一张包含 \(n\) 个结点与 \(m\) 条边的无向图,结点依次以 \(1,2,…,n\) 编号,第 \(i\) 条边(\(1≤i≤m\))连接结点 \(u_i\) 与结点 \(v_i\)。如果从一个结点经过若干条边可以到达另一个结点,则称这两个结点是连通的。

你需要向图中加入若干条边,使得图中任意两个结点都是连通的。请你求出最少需要加入的边的条数。

注意给出的图中可能包含重边与自环。

【输入】

第一行,两个正整数 \(n,m\),表示图的点数与边数。

接下来 \(m\) 行,每行两个正整数 \(u_i,v_i\),表示图中一条连接结点 \(u_i\) 与结点 \(v_i\) 的边。

【输出】

输出一行,一个整数,表示使得图中任意两个结点连通所需加入的边的最少数量。

【输入样例】

4 4
1 2
2 3
3 1
1 4

【输出样例】

0

【算法标签】

《洛谷 P14077 连通图》 #图论# #并查集# #深度优先搜索DFS# #连通块# #GESP# #2025#

【代码详解】

#include <bits/stdc++.h>
using namespace std;

const int N = 100005;  // 定义最大节点数

int n;                  // 节点数量
int m;                  // 边数量
int ans = 0;            // 存储连通分量数量
int p[N];               // 并查集父节点数组
bool vis[N];            // 标记数组,记录是否已统计过该连通分量

/**
 * 并查集查找函数(带路径压缩)
 * @param x 要查找的节点
 * @return 节点x的根节点
 */
int find(int x)
{
    if (p[x] != x)  // 如果当前节点不是根节点
    {
        p[x] = find(p[x]);  // 路径压缩
    }
    return p[x];
}

int main()
{
    // 输入节点数和边数
    cin >> n >> m;
    
    // 初始化并查集,每个节点的父节点指向自己
    for (int i = 1; i <= n; i++)
    {
        p[i] = i;
    }
    
    // 处理每条边,合并连通分量
    while (m--)
    {
        int a, b;
        cin >> a >> b;
        // 合并a和b所在的连通分量
        p[find(a)] = find(b);
    }
    
    // 统计连通分量数量
    for (int i = 1; i <= n; i++)
    {
        int x = find(i);  // 找到节点i的根节点
        if (!vis[x])      // 如果该连通分量未被统计过
        {
            ans++;        // 连通分量数量加1
            vis[x] = 1;   // 标记该连通分量已统计
        }
    }
    
    /**
     * 输出结果:
     * 连通分量数量减1,即需要添加的边数
     * 因为要将所有连通分量连接成一棵树需要ans-1条边
     */
    cout << ans - 1 << endl;
    
    return 0;
}

【运行结果】

4 4
1 2
2 3
3 1
1 4
0

P14078 金币收集

【题目来源】

洛谷:[P14078 GESP202509 七级] 金币收集 - 洛谷

【题目描述】

小 A 正在游玩收集金币的游戏。具体来说,在数轴上将会出现 \(n\) 枚金币,其中第 \(i\) 枚(\(1≤i≤n\))金币将会在时刻 \(t_i\) 出现在数轴上坐标为 \(x_i\) 的位置。小 A 必须在时刻 \(t_i\) 恰好位于坐标 \(x_i\),才可以获得第 \(i\) 枚金币。

游戏开始时为时刻 \(0\),此时小 A 的坐标为 \(0\)。正常来说,小 A 可以按游戏机的按键在数轴上左右移动,但不幸的是游戏机的左方向键失灵了。小 A 每个时刻只能选择保持不动,或是向右移动一个单位。换言之,如果小 A 在时刻 \(t\) 的坐标为 \(x\),那么他在时刻 \(t+1\) 的坐标只能是 \(x\) 或是 \(x+1\) 二者之一,分别对应保持不动和向右移动。

小 A 想知道他最多能收集多少枚金币。你能帮他收集最多的金币吗?

【输入】

第一行,一个正整数 \(n\),表示金币的数量。

接下来 \(n\) 行,每行两个正整数 \(x_i,t_i\),分别表示金币出现的坐标与时刻。

【输出】

输出一行,一个整数,表示小 A 最多能收集的金币数量。

【输入样例】

3
1 6
3 7
2 4

【输出样例】

2

【算法标签】

《洛谷 P14078 金币收集》 #线性DP# #GESP# #2025#

【代码详解】

#include <bits/stdc++.h>
using namespace std;

const int N = 100005;  // 定义最大数据量

int n;                  // 输入的数据对数
int maxn;               // 未使用的变量(可删除)
int len;                // 记录当前最长序列长度

// 定义节点结构体,存储x和t值
struct Node
{
    int x, t;
} a[N], b[N];           // a数组存储原始数据,b数组存储最长序列

/**
 * 比较函数,用于排序
 * @param x 第一个节点
 * @param y 第二个节点
 * @return 先按x升序,x相同按t升序
 */
bool cmp(Node x, Node y)
{
    if (x.x != y.x)
        return x.x < y.x;
    return x.t < y.t;
}

/**
 * 二分查找函数,寻找插入位置
 * @param x 要查找的节点
 * @return 合适的插入位置
 */
int find(Node x)
{
    int L = 1, R = len, mid;
    while (L < R)
    {
        mid = (L + R) / 2;
        if (x.x - b[mid].x > x.t - b[mid].t)
            R = mid;
        else
            L = mid + 1;
    }
    return L;
}

int main()
{
    cin >> n;
    int cur = 0;  // 记录有效数据数量
    
    // 输入并筛选有效数据(x <= t)
    for (int i = 1; i <= n; i++)
    {
        int x, t;
        cin >> x >> t;
        if (x <= t)
        {
            a[++cur].x = x;
            a[cur].t = t;
        }
    }
    
    // 对有效数据进行排序
    sort(a + 1, a + cur + 1, cmp);
    
    // 初始化最长序列
    len = 1;
    b[1] = a[1];
    
    // 构建最长满足条件的序列
    for (int i = 2; i <= cur; i++)
    {
        // 如果当前元素可以直接加入序列
        if (a[i].x - b[len].x <= a[i].t - b[len].t)
        {
            b[++len] = a[i];
        }
        // 否则找到合适的位置替换
        else
        {
            int j = find(a[i]);
            b[j] = a[i];
        }
    }
    
    // 输出最长序列长度
    cout << len << endl;
    
    return 0;
}

【运行结果】

3
1 6
3 7
2 4
2
posted @ 2026-01-15 08:57  热爱编程的通信人  阅读(6)  评论(0)    收藏  举报