2025年3月GESP真题及题解(C++七级): 图上移动

2025年3月GESP真题及题解(C++七级): 图上移动

题目描述

小 A 有一张包含 n n n 个结点与 m m m 条边的无向图,结点以 1 , 2 , ... , n 1, 2, \dots, n 1,2,...,n 标号。小 A 会从图上选择一个结点作为起点,每一步移动到某个与当前小 A 所在结点相邻的结点。对于每个结点 i i i ( 1 ≤ i ≤ n 1 \leq i \leq n 1≤i≤n),小 A 想知道从结点 i i i 出发恰好移动 1 , 2 , ... , k 1, 2, \dots, k 1,2,...,k 步之后,小 A 可能会位于哪些结点。由于满足条件的结点可能有很多,你只需要求出这些结点的数量。

输入格式

第一行,三个正整数 n , m , k n, m, k n,m,k,分别表示无向图的结点数与边数,最多移动的步数。

接下来 m m m 行,每行两个正整数 u i , v i u_i, v_i ui,vi,表示图中的一条连接结点 u i u_i ui 与 v i v_i vi 的无向边。

输出格式

共 n n n 行,第 i i i 行 ( 1 ≤ i ≤ n 1 \leq i \leq n 1≤i≤n) 包含 k k k 个整数,第 j j j 个整数 ( 1 ≤ j ≤ k 1 \leq j \leq k 1≤j≤k) 表示从结点 i i i 出发恰好移动 j j j 步之后可能位置的结点数量。

输入输出样例 1
输入 1
复制代码
4 4 3
1 2
1 3
2 3
3 4
输出 1
复制代码
2 4 4
2 4 4
3 3 4
1 3 3
说明/提示

对于 20 % 20\% 20% 的测试点,保证 k = 1 k = 1 k=1。

对于另外 20 % 20\% 20% 的测试点,保证 1 ≤ n ≤ 50 , 1 ≤ m ≤ 50 1 \leq n \leq 50, 1 \leq m \leq 50 1≤n≤50,1≤m≤50。

对于所有测试点,保证 1 ≤ n ≤ 500 , 1 ≤ m ≤ 500 , 1 ≤ k ≤ 20 , 1 ≤ u i , v i ≤ n 1 \leq n \leq 500, 1 \leq m \leq 500, 1 \leq k \leq 20, 1 \leq u_i, v_i \leq n 1≤n≤500,1≤m≤500,1≤k≤20,1≤ui,vi≤n。

思路分析

本题要求计算从每个结点出发,恰好移动 1 到 k 步后可能到达的不同结点数量。由于 k 较小(≤20),可以采用动态规划方法对每个起点单独计算。

对于每个起点 s:

  • 定义状态 dp[j][v] 表示从 s 出发恰好 j 步能否到达结点 v。
  • 初始状态:dp[0][s] = true,其余为 false。
  • 状态转移:对于步数 j 从 1 到 k,遍历每条边 (u, v),若 dp[j-1][u] 为 true,则 dp[j][v] 置为 true;同理,若 dp[j-1][v] 为 true,则 dp[j][u] 置为 true。因为是无向图,每条边可以双向行走。
  • 最终对于每个 j,统计 dp[j][v] 中 true 的数量即为答案。

时间复杂度:共 n 个起点,每个起点进行 k 轮转移,每轮遍历 m 条边,总复杂度 O(n * k * m),在题目数据范围(n,m ≤ 500, k ≤ 20)下完全可行。

代码实现

cpp 复制代码
#include <iostream>
#include <cstring>
using namespace std;

const int MAXN = 505;   // 最大结点数
const int MAXK = 25;    // 最大步数+5
const int MAXM = 505;   // 最大边数

bool dp[MAXK][MAXN];            // dp[步数][结点]:从当前起点出发恰好j步能否到达该结点
pair<int, int> edges[MAXM];     // 存储所有边

int main() {
    int n, m, k;
    cin >> n >> m >> k;

    // 读入边
    for (int i = 0; i < m; i++) {
        int u, v;
        cin >> u >> v;
        edges[i] = {u, v};      // 存为pair方便使用
    }

    // 对每个起点分别计算
    for (int start = 1; start <= n; start++) {
        // 初始化dp数组为false
        memset(dp, 0, sizeof(dp));
        // 0步时只能到达起点自身
        dp[0][start] = true;

        // 动态规划:计算恰好j步的可达性
        for (int j = 1; j <= k; j++) {
            // 遍历每条边进行转移
            for (int i = 0; i < m; i++) {
                int u = edges[i].first, v = edges[i].second;
                // 如果上一步能到达u,则这一步可以通过边(u,v)到达v
                if (dp[j - 1][u]) {
                    dp[j][v] = true;
                }
                // 无向图,反向同理
                if (dp[j - 1][v]) {
                    dp[j][u] = true;
                }
            }
        }

        // 输出结果:对于每个步数j,统计可达结点数量
        for (int j = 1; j <= k; j++) {
            int cnt = 0;
            for (int v = 1; v <= n; v++) {
                if (dp[j][v]) cnt++;
            }
            cout << cnt;
            if (j < k) cout << " ";   // 行内空格分隔
        }
        cout << endl;   // 换行进入下一个起点
    }

    return 0;
}

功能分析

  1. 输入处理

    • 读取结点数 n、边数 m 和最大步数 k。
    • 存储 m 条无向边。
  2. 核心计算

    • 外层循环遍历每个起点 start(1 到 n)。
    • 对每个起点,使用二维布尔数组 dp 记录可达性。
    • 动态规划过程模拟了所有可能的移动路径(允许重复访问结点和边)。
    • 通过遍历所有边进行状态转移,确保考虑所有可能的移动。
  3. 输出结果

    • 对每个起点,输出 k 个整数,分别表示移动 1 到 k 步后可能位置的数量。
  4. 算法特点

    • 利用 k 较小的条件,采用朴素的动态规划即可高效求解。
    • 每个起点独立计算,逻辑清晰,易于实现。
    • 正确处理无向边和自环(如果存在)的情况。
  5. 复杂度

    • 时间复杂度:O(n * k * m),最大为 500 × 20 × 500 = 5 × 10^6,运行速度快。
    • 空间复杂度:O(k * n + m),主要用于存储 dp 数组和边列表。

各种学习资料,助力大家一站式学习和提升!!!

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
int main(){
	cout<<"##########  一站式掌握信奥赛知识!  ##########";
	cout<<"#############  冲刺信奥赛拿奖!  #############";
	cout<<"######  课程购买后永久学习,不受限制!   ######";
	return 0;
}

1、csp信奥赛高频考点知识详解及案例实践:

CSP信奥赛C++动态规划:
https://blog.csdn.net/weixin_66461496/category_13096895.html点击跳转

CSP信奥赛C++标准模板库STL:
https://blog.csdn.net/weixin_66461496/category_13108077.html 点击跳转

信奥赛C++提高组csp-s知识详解及案例实践:
https://blog.csdn.net/weixin_66461496/category_13113932.html

2、csp信奥赛冲刺一等奖有效刷题题解:

CSP信奥赛C++初赛及复赛高频考点真题解析(持续更新):https://blog.csdn.net/weixin_66461496/category_12808781.html 点击跳转

CSP信奥赛C++一等奖通关刷题题单及题解(持续更新):https://blog.csdn.net/weixin_66461496/category_12673810.html 点击跳转

3、GESP C++考级真题题解:

GESP(C++ 一级+二级+三级)真题题解(持续更新):https://blog.csdn.net/weixin_66461496/category_12858102.html 点击跳转

GESP(C++ 四级+五级+六级)真题题解(持续更新):https://blog.csdn.net/weixin_66461496/category_12869848.html 点击跳转

GESP(C++ 七级+八级)真题题解(持续更新):
https://blog.csdn.net/weixin_66461496/category_13117178.html

4、CSP信奥赛C++竞赛拿奖视频课:

https://edu.csdn.net/course/detail/40437 点击跳转

· 文末祝福 ·

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
int main(){
	cout<<"跟着王老师一起学习信奥赛C++";
	cout<<"    成就更好的自己!       ";
	cout<<"  csp信奥赛一等奖属于你!   ";
	return 0;
}
相关推荐
编程大师哥2 小时前
C++ 中解锁 Redis
开发语言·c++·redis
王老师青少年编程2 小时前
2025年3月GESP真题及题解(C++七级): 等价消除
c++·编程·题解·真题·gesp·七级·等价消除
Yupureki2 小时前
《算法竞赛从入门到国奖》算法基础:入门篇-贪心算法(上)
c语言·数据结构·c++·算法·贪心算法·visual studio
散峰而望2 小时前
【算法竞赛】队列和 queue
开发语言·数据结构·c++·算法·链表·github·线性回归
yuanmenghao2 小时前
车载Linux 系统问题定位方法论与实战系列 - 开篇: 为什么需要一套“系统化”的 Linux 问题定位方法
linux·运维·服务器·数据结构·c++·自动驾驶
一只小bit2 小时前
Qt 对话框全方面详解,包含示例与解析
前端·c++·qt·cpp·页面
柏木乃一2 小时前
基础IO(上)
linux·服务器·c语言·c++·shell
e***98572 小时前
C++跨平台开发的5大核心挑战与突破
开发语言·c++
橘颂TA2 小时前
【剑斩OFFER】算法的暴力美学——leetCode 662 题:二叉树最大宽度
c++·算法·结构与算法