2025年12月GESP真题及题解(C++七级): 城市规划

2025年12月GESP真题及题解(C++七级): 城市规划

题目描述

A 国有 n n n 座城市,城市之间由 m m m 条双向道路连接,任意一座城市均可经过若干条双向道路到达另一座城市。城市依次以 1 , 2 , ... , n 1,2,\ldots,n 1,2,...,n 编号。第 i i i( 1 ≤ i ≤ m 1\le i\le m 1≤i≤m)条双向道路连接城市 u i u_i ui 与城市 v i v_i vi。

对于城市 u u u 和城市 v v v 而言,它们之间的连通度 d ( u , v ) d(u,v) d(u,v) 定义为从城市 u u u 出发到达城市 v v v 所需经过的双向道路的最少条数。由于道路是双向的,可以知道连通度满足 d ( u , v ) = d ( v , u ) d(u,v)=d(v,u) d(u,v)=d(v,u),特殊地有 d ( u , u ) = 0 d(u,u)=0 d(u,u)=0。

现在 A 国正在规划城市建设方案。城市 u u u 的建设难度为它到其它城市的最大连通度。请你求出建设难度最小的城市,如果有多个满足条件的城市,则选取其中编号最小的城市。形式化地,你需要求出使得 max ⁡ 1 ≤ i ≤ n d ( u , i ) \max\limits_{1\le i\le n}d(u,i) 1≤i≤nmaxd(u,i) 最小的 u u u,若存在多个可能的 u u u 则选取其中最小的。

输入格式

第一行,两个正整数 n , m n,m n,m,表示 A 国的城市数量与双向道路数量。

接下来 m m m 行,每行两个整数 u i , v i u_i,v_i ui,vi,表示一条连接城市 u i u_i ui 与城市 v i v_i vi 的双向道路。

输出格式

输出一行,一个整数,表示建设难度最小的城市编号。如果有多个满足条件的城市,则选取其中编号最小的城市。

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

对于 40 % 40\% 40% 的测试点,保证 1 ≤ n ≤ 300 1\le n\le 300 1≤n≤300。

对于所有测试点,保证 1 ≤ n ≤ 2000 1\le n\le 2000 1≤n≤2000, 1 ≤ m ≤ 2000 1\le m\le 2000 1≤m≤2000, 1 ≤ u i , v i ≤ n 1\le u_i,v_i\le n 1≤ui,vi≤n。

思路分析

这个问题实际上是在求图的中心点(center of a graph):

  • 对于每个节点,计算它到所有其他节点的最短距离中的最大值(这称为该节点的离心率/eccentricity
  • 找出离心率最小的节点,如果多个节点离心率相同,选择编号最小的
关键点:
  1. 连通图保证:题目说明任意城市均可到达另一座城市,所以图是连通的
  2. 边权为1:每条道路的长度视为1,所以连通度就是最短路径的边数
  3. n ≤ 2000, m ≤ 2000:可以直接对每个节点做BFS求最短路径
算法选择:
  • 对每个节点运行BFS,计算它到所有其他节点的距离
  • 记录每个节点的最大距离(离心率)
  • 比较所有节点的离心率,找到最小值对应的最小节点编号

时间复杂度:O(n(n+m)) = O(n² + nm),在n=2000, m=2000时最多约8×10⁶次操作,可以接受

代码实现

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

const int N = 2005;  // 最大城市数
const int INF = 1e9; // 无穷大值

vector<int> g[N];    // 邻接表存储图
int n, m;           // 城市数,道路数

// 从起点s开始BFS,返回从s到所有节点的最短距离
vector<int> bfs(int s) {
    vector<int> dist(n + 1, -1);  // 距离数组,初始化为-1表示未访问
    queue<int> q;
    
    dist[s] = 0;    // 起点距离为0
    q.push(s);
    
    while (!q.empty()) {
        int u = q.front();
        q.pop();
        
        // 遍历所有邻接节点
        for (int v : g[u]) {
            if (dist[v] == -1) {  // 如果节点v未访问过
                dist[v] = dist[u] + 1;  // 更新距离
                q.push(v);              // 加入队列
            }
        }
    }
    
    return dist;
}

int main() {
    // 输入数据
    cin >> n >> m;
    
    // 读取m条边,构建无向图
    for (int i = 0; i < m; i++) {
        int u, v;
        cin >> u >> v;
        g[u].push_back(v);
        g[v].push_back(u);  // 无向图,双向添加
    }
    
    int min_e = INF;  // 最小离心率(建设难度)
    int best_city = 0;           // 最佳城市编号
    
    // 对每个城市计算离心率
    for (int i = 1; i <= n; i++) {
        // 运行BFS获取从i到所有节点的距离
        vector<int> dist = bfs(i);
        
        // 计算离心率:从i到其他所有节点的最大距离
        int e = 0;
        for (int j = 1; j <= n; j++) {
            e= max(e, dist[j]);
        }
        
        // 更新最优城市
        if (e< min_e) {
            min_e = e;
            best_city = i;
        }
        // 如果离心率相同,选择编号更小的
        else if (e== min_e && i < best_city) {
            best_city = i;
        }
    }
    
    // 输出结果
    cout << best_city << endl;
    
    return 0;
}

代码解释

数据结构
  • vector<int> g[N]:邻接表存储图,g[u]存储与城市u直接相连的所有城市
  • vector<int> dist:BFS中的距离数组,dist[i]表示从起点到城市i的最短距离
BFS函数
  • 参数:起点s
  • 功能:使用BFS计算从s到所有节点的最短距离
  • 返回值:距离数组,dist[i]为从s到i的最短距离
主函数逻辑
  1. 输入处理:读取n,m,构建无向图的邻接表
  2. 离心率计算 :对每个城市i:
    • 调用BFS(i)获取从i出发的最短距离
    • 找出所有距离中的最大值,即离心率
  3. 最优选择
    • 如果离心率比当前最小值小,更新最小值和最佳城市
    • 如果离心率相等但编号更小,更新最佳城市
  4. 输出结果:打印最佳城市编号

功能分析

1. 正确性保证
  • BFS保证计算的是最短路径(因为边权为1)
  • 遍历所有节点计算离心率,不会遗漏
  • 比较逻辑正确处理了多个最优解的情况
2. 时间复杂度
  • 每个节点执行一次BFS:O(n+m)
  • 总复杂度:O(n(n+m)) = O(n²+nm)
  • 最坏情况:n=2000, m=2000,约8×10⁶次操作,完全可行
3. 空间复杂度
  • 邻接表:O(n+m)
  • BFS队列和距离数组:O(n)
  • 总空间:O(n+m) ≤ O(4000),非常高效
4. 边界情况处理
  • 图连通:题目保证,不需要额外检查
  • 自环和重边:不影响BFS正确性
  • 多个最优解:比较逻辑确保选择编号最小的

示例验证

示例1
复制代码
3 3
1 2
1 3
2 3

这是一个完全图(三角形):

  • 城市1:到2距离1,到3距离1 → 离心率=1
  • 城市2:到1距离1,到3距离1 → 离心率=1
  • 城市3:到1距离1,到2距离1 → 离心率=1
    离心率相同,选择编号最小的1
示例2
复制代码
4 4
1 2
2 3
3 4
2 4

图结构:1-2-3-4,且2-4相连

  • 城市1:到2(1), 3(2), 4(2) → 离心率=2
  • 城市2:到1(1), 3(1), 4(1) → 离心率=1 ← 最小
  • 城市3:到1(2), 2(1), 4(1) → 离心率=2
  • 城市4:到1(2), 2(1), 3(1) → 离心率=2
    选择城市2

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

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;
}
相关推荐
寻星探路3 小时前
【算法专题】滑动窗口:从“无重复字符”到“字母异位词”的深度剖析
java·开发语言·c++·人工智能·python·算法·ai
我叫袁小陌3 小时前
C++多线程全面详解
开发语言·c++
m0_748250034 小时前
C++ 官方文档与标准
开发语言·c++
matlabgoodboy4 小时前
程序代做python代编程matlab定制代码编写C++代写plc设计java帮做
c++·python·matlab
DYS_房东的猫5 小时前
《 C++ 零基础入门教程》第6章:模板与 STL 算法 —— 写一次,用万次
开发语言·c++·算法
点云SLAM5 小时前
C++ 静态初始化顺序问题(SIOF)和SLAM / ROS 工程实战问题
开发语言·c++·slam·静态初始化顺序问题·工程实战技术·c++static 关键字
pen-ai5 小时前
打通 Python 与 C++ 的参数传递机制
开发语言·c++·python
王老师青少年编程6 小时前
信奥赛C++提高组csp-s之KMP算法详解
c++·kmp·字符串匹配·csp·信奥赛·csp-s·提高组
喵星人工作室6 小时前
C++传说:神明之剑0.4.5装备机制彻底完成
开发语言·c++·游戏