蓝桥杯(C 语言 / C++)备考全攻略:3-6 个月从入门到上岸,语法 / 算法 / 真题 + 模板直接用
蓝桥杯作为国内极具含金量的编程竞赛,是大学生提升编程能力、丰富简历的重要选择。本文针对 C 语言 / C++ 方向,打造 3-6 个月备考计划,从语法基础到算法进阶,再到真题实战,梳理高频考点并提供可直接复用的代码模板,帮你高效备考、稳步上岸。
一、备考规划:3-6 个月阶段拆解(零基础友好)
1. 基础阶段(1-2 个月):夯实语法与工具
核心目标:掌握 C/C++ 基础语法,熟练使用编译器(Dev-C++/VS Code),能独立编写简单程序。
每日学习时长:2-3 小时。
(1)语法重点(按优先级排序)
- 核心语法:变量 / 常量、数据类型(int/long long/double/char)、运算符(算术 / 逻辑 / 位运算)、分支(if-else/switch)、循环(for/while/do-while)—— 这是所有题目的基础,务必熟练。
- 数组与字符串:一维数组(存储数据)、二维数组(矩阵问题)、字符串处理(strlen/strcpy/strcmp,C++ 可多用 string 类)。
- 函数与指针:函数定义 / 调用 / 递归(递归是蓝桥杯高频考点,如斐波那契、阶乘)、指针基础(地址与取值、指针与数组结合)。
- 结构体与 STL(C++ 重点):结构体(自定义数据类型,如存储学生信息、坐标)、STL 容器(vector 动态数组、queue 队列、stack 栈、map 键值对 ——C++ 选手必学,能大幅简化代码)。
(2)工具与练习
- 编译器选择:推荐 Dev-C++(轻量、兼容性好,蓝桥杯竞赛环境类似)或 VS Code(需配置 MinGW)。
- 练习平台:洛谷 “入门题库”(P1000-P1050)、蓝桥杯官网 “基础练习”,每天做 2-3 道基础题,巩固语法。
2. 算法进阶阶段(2-3 个月):突破高频算法
核心目标:掌握蓝桥杯常考算法,能独立解决中等难度题目(如模拟、枚举、动态规划)。
每日学习时长:3-4 小时
(1)高频算法模块(蓝桥杯 90% 题目覆盖)
按 “易得分→难突破” 排序,优先掌握前 5 个模块:
| 算法模块 | 核心考点 | 典型题目 |
|---|---|---|
| 模拟与枚举 | 暴力枚举(循环遍历)、模拟过程(如日期计算) | 蓝桥杯 “基础练习・回文数”“大臣的旅费” |
| 递归与递推 | 递归函数设计、递推公式(斐波那契、递推数列) | “基础练习・斐波那契数列”“瓷砖铺放” |
| 排序与查找 | 快速排序 / 冒泡排序、二分查找(整数 / 浮点数) | “基础练习・排序”“查找整数” |
| 动态规划(DP) | 线性 DP(最大子序和、最长递增子序列)、背包问题(01 背包、完全背包) | “地宫取宝”“剪绳子” |
| 数学问题 | 素数判定、最大公约数(gcd)、最小公倍数(lcm)、阶乘、组合数 | “基础练习・素数判断”“分解质因数” |
| 图论基础 | 深度优先搜索(DFS)、广度优先搜索(BFS) | “迷宫问题”“岛屿数量” |
| 贪心算法 | 局部最优解推导全局最优(如活动安排、区间问题) | “独木桥”“排队打水” |
(2)学习方法
- 算法理解:先看算法原理(推荐《算法图解》《啊哈算法》,零基础友好),再手动模拟过程(如递归的调用栈、DP 的状态转移表)。
- 代码实现:每学一个算法,先独立写代码,再对比标准题解,修正逻辑漏洞(如递归的终止条件、DP 的初始化)。
3. 真题冲刺阶段(1 个月):实战复盘 + 模板固化
核心目标:适应蓝桥杯题型(填空 + 编程),掌握答题技巧,优化时间分配。每日学习时长:3-4 小时
(1)真题选择与训练
- 真题来源:近 5 年蓝桥杯省赛真题(C 语言 / C++ B 组,省赛是上岸关键,难度低于国赛)、蓝桥杯官网 “历届试题”。
- 训练方式:
- 填空题型:重点练 “手算 + 代码验证”,如数学题、小模拟(填空题占 40 分,正确率直接决定是否晋级)。
- 编程题型:按 “1 小时内完成 1 道题” 训练,写完后对照题解优化代码(如减少时间复杂度、处理边界条件)。
(2)复盘重点
- 错题分类:将错题按 “语法错误”“算法思路错误”“边界条件遗漏” 分类,每周复盘 1 次,避免重复踩坑。
- 时间优化:记录每道题的耗时,优先保证简单题(前 4 题)正确率,难题(后 2 题)可先写暴力思路,拿到部分分数(蓝桥杯有部分分机制)。
二、高频考点梳理:直击蓝桥杯得分点
1. 语法高频考点(避坑指南)
- 字符串处理:C 语言中字符串以
'\0'结尾,用strlen计算长度时不要漏算;C++ 用 string 类更方便(如s.size()获取长度、s.substr()截取子串)。 - 循环边界:枚举时注意 “左闭右开” 还是 “左闭右闭”,如遍历数组
for (int i = 0; i < n; i++)(n 为数组长度,避免越界)。
数据类型溢出:int 范围(-2³¹~2³¹-1,约 2e9),涉及 “大数计算”(如阶乘、求和)时,务必用 long long(范围 - 9e18~9e18)。c
// 错误示例:int存储大数导致溢出 int sum = 0; for (int i = 1; i <= 1e5; i++) sum += i; // sum会溢出 // 正确示例:用long long long long sum = 0; for (int i = 1; i <= 1e5; i++) sum += i; 2. 算法高频考点(代码模板直接用)
(1)数学模块:素数判定 + gcd+lcm
// 1. 素数判定(判断n是否为素数,n>=2) bool is_prime(int n) { if (n <= 1) return false; for (int i = 2; i * i <= n; i++) { // 优化:i到sqrt(n)即可 if (n % i == 0) return false; } return true; } // 2. 最大公约数(gcd,欧几里得算法) int gcd(int a, int b) { return b == 0 ? a : gcd(b, a % b); } // 3. 最小公倍数(lcm,公式:lcm(a,b) = a*b / gcd(a,b),先算gcd避免溢出) int lcm(int a, int b) { return a / gcd(a, b) * b; // 先除后乘,减少溢出风险 } (2)动态规划:01 背包(选 / 不选物品,求最大价值)
// 01背包模板:n个物品,每个物品体积v[i],价值w[i],背包容量m,求最大价值 int knapsack_01(int n, int m, int v[], int w[]) { int dp[1005] = {0}; // dp[j]:容量为j时的最大价值 for (int i = 1; i <= n; i++) { // 遍历物品 for (int j = m; j >= v[i]; j--) { // 逆序遍历容量,避免重复选 dp[j] = max(dp[j], dp[j - v[i]] + w[i]); } } return dp[m]; } (3)搜索:BFS(最短路径,如迷宫问题)
#include <queue> using namespace std; // BFS模板:迷宫(n行m列,0可走,1障碍,求从(0,0)到(n-1,m-1)的最短步数) int dx[] = {0, 0, 1, -1}; // 上下左右四个方向 int dy[] = {1, -1, 0, 0}; int bfs(int n, int m, int grid[][1005]) { int dist[1005][1005] = {0}; // 记录步数,初始为0(未访问) queue<pair<int, int>> q; q.push({0, 0}); dist[0][0] = 1; // 起点步数为1 while (!q.empty()) { auto [x, y] = q.front(); // C++17特性,也可拆分为int x = q.front().first; q.pop(); if (x == n-1 && y == m-1) return dist[x][y]; // 到达终点,返回步数 for (int i = 0; i < 4; i++) { // 遍历四个方向 int nx = x + dx[i], ny = y + dy[i]; // 检查是否越界、是否可走、是否未访问 if (nx >= 0 && nx < n && ny >=0 && ny < m && grid[nx][ny] == 0 && dist[nx][ny] == 0) { dist[nx][ny] = dist[x][y] + 1; q.push({nx, ny}); } } } return -1; // 无法到达终点 } (4)排序:快速排序(C 语言实现)
// 快速排序模板:排序数组a[left..right] void quick_sort(int a[], int left, int right) { if (left >= right) return; int pivot = a[left]; // 基准值(选左端点) int i = left, j = right; while (i < j) { // 从右找比基准小的数 while (i < j && a[j] >= pivot) j--; a[i] = a[j]; // 从左找比基准大的数 while (i < j && a[i] <= pivot) i++; a[j] = a[i]; } a[i] = pivot; // 基准值归位 quick_sort(a, left, i-1); // 排序左半部分 quick_sort(a, i+1, right); // 排序右半部分 } 三、备考工具与资源推荐
1. 学习资源
- 视频教程:b 站 “蓝桥杯 C/C++”(推荐 “算法零基础 100 讲”“正月点灯笼”,零基础友好,结合真题讲解)。
- 书籍:《算法竞赛入门经典(第 2 版)》(刘汝佳,蓝桥杯备考圣经)、《C++ Primer Plus》(语法基础)。
- 官网资源:蓝桥杯官网 —— 真题、比赛规则、报名信息全在这。
2. 练习平台
- 洛谷:—— 真题题库全,支持在线判题,可按 “蓝桥杯” 标签筛选题目。
- 蓝桥杯练习系统:—— 官方练习平台,题型与竞赛一致,适合模拟训练。
四、考场答题技巧:多拿 10 分的关键
- 填空题优先做:填空题占 40 分(共 8 题,每题 5 分),难度低、耗时短,优先保证正确率(如数学题可手算 + 代码验证)。
- 编程题 “暴力” 先行:遇到难题(如 DP、图论),先写暴力解法(如枚举所有可能),拿到部分分数(蓝桥杯按测试用例给分,暴力能过 30%-50% 用例)。
- 代码规范:变量名清晰(如
n表示数量、dp表示动态规划数组)、加简单注释(如 “// BFS 初始化队列”),避免因逻辑混乱丢分。 - 时间分配:省赛共 4 小时,建议填空题 1 小时内完成,编程题前 4 题 2 小时,后 2 题 1 小时(难题不纠结,优先保简单题)。
五、常见问题解答(FAQ)
1. 零基础 3 个月能上岸吗?
能!蓝桥杯省赛 B 组难度适中,3 个月内聚焦 “基础语法 + 高频算法(模拟、枚举、递归、简单 DP)”,每天坚持 2-3 小时,大概率能晋级(省赛前 50% 可晋级国赛)。
2. C 语言和 C++ 选哪个?
推荐 C++!C++ 兼容 C 语言语法,且 STL 容器(vector、queue 等)能大幅简化代码(如动态数组不用手动管理内存),对算法题更友好。
3. 真题要刷多少套?
至少刷近 5 年省赛真题(共 5 套),每套刷 2 遍:第一遍按考试时间模拟,第二遍复盘错题,固化模板(如 BFS、01 背包的代码结构)。
六、高频算法模块真题解析(C/C++ 实现)
以下针对模拟与枚举、递归与递推等 7 大算法模块,逐一提供典型题目的完整代码与核心思路,代码可直接复用,注释详细便于理解。
(一)、模拟与枚举模块
典型题目 1:基础练习・回文数(蓝桥杯官网)
题目要求
判断一个 5 位数是否为回文数(如 12321,个位与万位相同,十位与千位相同)。
核心思路
- 提取 5 位数的每一位(万位、千位、十位、个位);
- 比较万位与个位、千位与十位是否相等。
代码实现
#include <stdio.h> int main() { int num; scanf("%d", &num); // 输入5位数(范围10000~99999) // 提取每一位 int wan = num / 10000; // 万位 int qian = (num / 1000) % 10; // 千位 int shi = (num / 10) % 10; // 十位 int ge = num % 10; // 个位 // 判断是否为回文数 if (wan == ge && qian == shi) { printf("yes\n"); } else { printf("no\n"); } return 0; } 典型题目 2:大臣的旅费(蓝桥杯省赛)
题目要求
某国大臣从首都出发,遍历所有城市(城市间道路为单向,距离为 1),求最长旅行路线的距离(即最多经过多少个城市)。
核心思路
- 用邻接表存储城市间的道路关系;
- 两次 DFS:第一次从首都出发找到最远的城市 A,第二次从 A 出发找到最远的城市 B,A 到 B 的距离即为最长距离。
代码实现
#include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX 10001 // 假设城市数量不超过10000 // 邻接表节点 typedef struct Node { int to; // 目标城市 struct Node* next; // 下一个节点 } Node; Node* adj[MAX]; // 邻接表 int max_dist; // 最大距离 int far_city; // 最远城市 // 添加边(单向) void add_edge(int from, int to) { Node* new_node = (Node*)malloc(sizeof(Node)); new_node->to = to; new_node->next = adj[from]; adj[from] = new_node; } // DFS:从start出发,记录当前距离 void dfs(int start, int dist) { if (dist > max_dist) { max_dist = dist; far_city = start; } Node* p = adj[start]; while (p != NULL) { dfs(p->to, dist + 1); // 每走一条路,距离+1 p = p->next; } } int main() { int n; // 城市数量 scanf("%d", &n); // 初始化邻接表 memset(adj, NULL, sizeof(adj)); for (int i = 0; i < n - 1; i++) { // n个城市有n-1条道路(树结构) int a, b; scanf("%d%d", &a, &b); add_edge(a, b); add_edge(b, a); // 题目隐含道路双向,若单向则删除此句 } // 第一次DFS:找最远城市 max_dist = 0; dfs(1, 0); // 假设首都为1号城市 // 第二次DFS:从最远城市找最长距离 max_dist = 0; dfs(far_city, 0); // 最长距离对应的旅费(题目隐含公式:10*max_dist + max_dist*(max_dist+1)/2) printf("%d\n", 10 * max_dist + max_dist * (max_dist + 1) / 2); return 0; } (二)、递归与递推模块
典型题目 1:基础练习・斐波那契数列(蓝桥杯官网)
题目要求
求斐波那契数列的第 n 项(n≤40),数列定义:F (1)=1,F (2)=1,F (n)=F (n-1)+F (n-2)。
核心思路
- 递归:直接按公式调用自身(适合 n 较小);
- 递推:用循环迭代计算(避免递归栈溢出,效率更高)。
代码实现(递推版,更高效)
#include <stdio.h> int main() { int n; scanf("%d", &n); if (n == 1 || n == 2) { printf("1\n"); return 0; } int a = 1, b = 1, res; // a=F(n-2), b=F(n-1) for (int i = 3; i <= n; i++) { res = a + b; a = b; // 更新F(n-2)为原F(n-1) b = res; // 更新F(n-1)为新结果 } printf("%d\n", res); return 0; } 典型题目 2:瓷砖铺放(蓝桥杯省赛)
题目要求
用 1×2 的瓷砖铺满 2×n 的地面,求有多少种铺法(n≤30)。
核心思路
- 递推公式:f (n) = f (n-1) + f (n-2)(n≥3);
- 解释:铺到 2×n 时,若最后一块竖放,剩余 2×(n-1)(对应 f (n-1));若最后两块横放,剩余 2×(n-2)(对应 f (n-2))。
- 初始条件:f (1)=1,f (2)=2。
代码实现
#include <stdio.h> int main() { int n; scanf("%d", &n); long long f[31]; // n=30时结果超int,用long long f[1] = 1; f[2] = 2; for (int i = 3; i <= n; i++) { f[i] = f[i-1] + f[i-2]; } printf("%lld\n", f[n]); return 0; } (三)、排序与查找模块
典型题目 1:基础练习・排序(蓝桥杯官网)
题目要求
对 n 个整数按从小到大排序并输出(n≤1000)。
核心思路
用快速排序(高效,时间复杂度 O (nlogn)),或冒泡排序(简单,适合 n 小)。
代码实现(快速排序版)
#include <stdio.h> // 快速排序:排序数组a[left..right] void quick_sort(int a[], int left, int right) { if (left >= right) return; int pivot = a[left]; // 基准值(选左端点) int i = left, j = right; while (i < j) { // 从右找比基准小的数 while (i < j && a[j] >= pivot) j--; a[i] = a[j]; // 从左找比基准大的数 while (i < j && a[i] <= pivot) i++; a[j] = a[i]; } a[i] = pivot; // 基准值归位 quick_sort(a, left, i-1); // 排序左半部分 quick_sort(a, i+1, right); // 排序右半部分 } int main() { int n, a[1001]; scanf("%d", &n); for (int i = 0; i < n; i++) { scanf("%d", &a[i]); } quick_sort(a, 0, n-1); // 输出排序结果 for (int i = 0; i < n; i++) { printf("%d ", a[i]); } return 0; } 典型题目 2:查找整数(蓝桥杯官网)
题目要求
在 n 个整数中查找给定的 x,若找到则输出其位置(从 1 开始),未找到则输出 - 1。
核心思路
- 顺序查找:遍历数组逐一对比(适合未排序数组);
- 二分查找:需先排序,再按 “折半” 规则查找(效率更高,适合 n 大)。
代码实现(顺序查找版,简单直接)
#include <stdio.h> int main() { int n, x, a[1001]; scanf("%d", &n); for (int i = 0; i < n; i++) { scanf("%d", &a[i]); } scanf("%d", &x); // 顺序查找 for (int i = 0; i < n; i++) { if (a[i] == x) { printf("%d\n", i+1); // 位置从1开始 return 0; } } // 未找到 printf("-1\n"); return 0; } (四)、动态规划(DP)模块
典型题目 1:地宫取宝(蓝桥杯省赛)
题目要求
地宫有 n 行 m 列格子,每个格子有一定价值的宝物(价值≥0),从左上角 (0,0) 出发,只能向右或向下走,每步取当前格子宝物,求到达右下角 (n-1,m-1) 时,宝物总价值≥k 的路径数(n,m≤50,k≤1000)。
核心思路
- 状态定义:
dp[i][j][v][c]表示到达 (i,j) 时,取了 c 件宝物,总价值为 v 的路径数; - 转移方程:从上方 (i-1,j) 或左方 (i,j-1) 转移而来,累加路径数;
- 初始条件:
dp[0][0][a[0][0]][1] = 1(起点取 1 件宝物,价值为格子值)。
代码实现
#include <stdio.h> #include <string.h> #define MOD 1000000007 // 题目要求结果取模 int main() { int n, m, k; scanf("%d%d%d", &n, &m, &k); int a[51][51]; // 存储地宫宝物价值 for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { scanf("%d", &a[i][j]); } } // dp[i][j][v][c]:到达(i,j),价值v,取c件的路径数 int dp[51][51][1001][51] = {0}; // 初始状态:起点(0,0) if (a[0][0] <= k) { dp[0][0][a[0][0]][1] = 1; } // 填充DP表 for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { // 跳过起点(已初始化) if (i == 0 && j == 0) continue; // 遍历可能的价值和宝物数量 for (int v = 0; v <= k; v++) { for (int c = 1; c <= 50; c++) { // 从上方(i-1,j)转移 if (i > 0) { int prev_v = v - a[i][j]; if (prev_v >= 0 && c > 0) { dp[i][j][v][c] = (dp[i][j][v][c] + dp[i-1][j][prev_v][c-1]) % MOD; } } // 从左方(i,j-1)转移 if (j > 0) { int prev_v = v - a[i][j]; if (prev_v >= 0 && c > 0) { dp[i][j][v][c] = (dp[i][j][v][c] + dp[i][j-1][prev_v][c-1]) % MOD; } } } } } } // 统计总价值≥k的所有路径数 int res = 0; for (int v = k; v <= 1000; v++) { for (int c = 1; c <= 50; c++) { res = (res + dp[n-1][m-1][v][c]) % MOD; } } printf("%d\n", res); return 0; } 典型题目 2:剪绳子(蓝桥杯省赛)
题目要求
把长度为 n 的绳子剪成 m 段(m≥2),每段长度为整数,求每段长度乘积的最大值(n≤100)。
核心思路
- 状态定义:
dp[i]表示长度为 i 的绳子的最大乘积; - 转移方程:
dp[i] = max(dp[i], max(j * (i-j), j * dp[i-j]))(j 从 1 到 i-1,j 为第一段长度); - 初始条件:
dp[2] = 1(长度 2 只能剪 1+1,乘积 1)。
代码实现
#include <stdio.h> #include <math.h> int main() { int n; scanf("%d", &n); int dp[101]; dp[2] = 1; // 初始条件 for (int i = 3; i <= n; i++) { dp[i] = 0; // 初始化当前最大乘积为0 // 遍历第一段长度j(1~i-1) for (int j = 1; j < i; j++) { // 两种情况:j不剪,j剪(用dp[j]) int temp = fmax(j * (i - j), j * dp[i - j]); dp[i] = fmax(dp[i], temp); } } printf("%d\n", dp[n]); return 0; } (五)、数学问题模块
典型题目 1:基础练习・素数判断(蓝桥杯官网)
题目要求
判断一个数是否为素数(大于 1 的自然数,除 1 和自身外无其他因数)。
核心思路
- 若 n≤1:不是素数;
- 若 n=2:是素数;
- 若 n 为偶数:不是素数;
- 遍历 2 到√n,若有能整除 n 的数:不是素数,否则是素数。
代码实现
#include <stdio.h> #include <math.h> int is_prime(int n) { if (n <= 1) return 0; // 不是素数 if (n == 2) return 1; // 是素数 if (n % 2 == 0) return 0; // 偶数不是素数 // 遍历到sqrt(n),步长为2(只看奇数) for (int i = 3; i <= sqrt(n); i += 2) { if (n % i == 0) return 0; } return 1; } int main() { int n; scanf("%d", &n); if (is_prime(n)) { printf("yes\n"); } else { printf("no\n"); } return 0; } 典型题目 2:分解质因数(蓝桥杯官网)
题目要求
将一个正整数分解为质因数的乘积(如 12=223)。
核心思路
- 从最小质因数 2 开始,依次尝试整除 n;
- 若能整除,记录该因数,并用商继续分解(重复除以该因数,直到不能整除);
- 若不能整除,因数加 1,重复步骤 2,直到商为 1。
代码实现
#include <stdio.h> int main() { int n; scanf("%d", &n); printf("%d=", n); int flag = 0; // 标记是否已输出过因数(用于控制乘号) for (int i = 2; i <= n; i++) { // 循环除以当前因数i,直到不能整除 while (n % i == 0) { if (flag) { printf("*"); // 非第一个因数前加乘号 } printf("%d", i); flag = 1; n /= i; // 用商继续分解 } } printf("\n"); return 0; } (六)、图论基础模块
典型题目 1:迷宫问题(蓝桥杯省赛)
题目要求
给定 n 行 m 列的迷宫(0 = 可走,1 = 障碍),从左上角 (0,0) 出发,每次可上下左右移动,求到达右下角 (n-1,m-1) 的最短步数。若无法到达,输出 - 1。
核心思路
用 BFS(广度优先搜索),逐层扩散,首次到达终点即最短路径:
- 方向数组存储上下左右 4 个移动方向;
- 距离数组记录步数(同时标记是否访问);
- 队列存储待访问坐标,按 “先进先出” 原则处理。
代码实现
#include <stdio.h> #include <stdlib.h> #define MAX 100 // 假设迷宫最大100x100 // 队列节点(存储坐标) typedef struct { int x, y; } Node; int main() { int n, m; scanf("%d%d", &n, &m); int grid[MAX][MAX]; for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { scanf("%d", &grid[i][j]); } } // 方向数组:上下左右 int dx[] = {0, 0, 1, -1}; int dy[] = {1, -1, 0, 0}; int dist[MAX][MAX] = {0}; // 距离+访问标记(0=未访问) Node queue[MAX * MAX]; int front = 0, rear = 0; // 队列首尾指针 // 起点入队 queue[rear].x = 0; queue[rear].y = 0; rear++; dist[0][0] = 1; // 起点步数为1 while (front < rear) { // 取出队首 Node curr = queue[front]; front++; // 到达终点 if (curr.x == n-1 && curr.y == m-1) { printf("%d\n", dist[curr.x][curr.y] - 1); // 步数=距离-1(起点算0步) return 0; } // 遍历4个方向 for (int i = 0; i < 4; i++) { int nx = curr.x + dx[i]; int ny = curr.y + dy[i]; // 检查边界、是否可走、是否未访问 if (nx >= 0 && nx < n && ny >= 0 && ny < m && grid[nx][ny] == 0 && dist[nx][ny] == 0) { dist[nx][ny] = dist[curr.x][curr.y] + 1; queue[rear].x = nx; queue[rear].y = ny; rear++; } } } // 无法到达 printf("-1\n"); return 0; } 典型题目 2:岛屿数量(蓝桥杯模拟题)
题目要求
给定 n 行 m 列的网格(0 = 海洋,1 = 陆地),相邻陆地(上下左右)组成岛屿,求岛屿总数。
核心思路
用 DFS(深度优先搜索):
- 遍历网格,遇到未访问的陆地(1)时,岛屿数 + 1;
- 对该陆地进行 DFS,将所有相连的陆地标记为已访问(避免重复计数)。
代码实现
#include <stdio.h> #include <string.h> #define MAX 100 int grid[MAX][MAX]; int visited[MAX][MAX]; int n, m; // 方向数组:上下左右 int dx[] = {0, 0, 1, -1}; int dy[] = {1, -1, 0, 0}; // DFS:标记所有相连的陆地 void dfs(int x, int y) { visited[x][y] = 1; // 标记为已访问 for (int i = 0; i < 4; i++) { int nx = x + dx[i]; int ny = y + dy[i]; // 检查边界、是否为陆地、是否未访问 if (nx >= 0 && nx < n && ny >= 0 && ny < m && grid[nx][ny] == 1 && !visited[nx][ny]) { dfs(nx, ny); } } } int main() { scanf("%d%d", &n, &m); for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { scanf("%d", &grid[i][j]); } } memset(visited, 0, sizeof(visited)); int count = 0; // 岛屿数量 for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { // 遇到未访问的陆地,启动DFS if (grid[i][j] == 1 && !visited[i][j]) { count++; dfs(i, j); } } } printf("%d\n", count); return 0; } (七)、贪心算法模块
典型题目 1:独木桥(蓝桥杯省赛)
题目要求
n 个士兵在长度为 L 的独木桥上(位置为 1~L),士兵只能向左或向右走,速度为 1 单位 / 秒,相遇时会转身继续走。求所有士兵离开桥的最短时间和最长时间。
核心思路
- 关键 insight:士兵相遇转身等价于 “互相穿过”(不影响离开时间);
- 最短时间:每个士兵到最近桥端的距离的最大值(取所有士兵 min (pos, L+1-pos) 的最大值);
- 最长时间:每个士兵到最远桥端的距离的最大值(取所有士兵 max (pos, L+1-pos) 的最大值)。
代码实现
#include <stdio.h> #include <math.h> int main() { int L, n; scanf("%d%d", &L, &n); int min_time = 0, max_time = 0; for (int i = 0; i < n; i++) { int pos; scanf("%d", &pos); // 最近桥端距离 int min_dist = fmin(pos, L + 1 - pos); // 最远桥端距离 int max_dist = fmax(pos, L + 1 - pos); if (min_dist > min_time) min_time = min_dist; if (max_dist > max_time) max_time = max_dist; } printf("%d %d\n", min_time, max_time); return 0; } 典型题目 2:排队打水(蓝桥杯模拟题)
题目要求
n 个人排队打水,第 i 个人打水时间为 t [i],求所有人的平均等待时间(等待时间 = 自己打水前所有人的打水时间之和)。
核心思路
贪心策略:按打水时间从小到大排序,让快的人先打,总等待时间最短(平均等待时间也最短)。
代码实现
#include <stdio.h> #include <stdlib.h> // 比较函数(用于qsort排序) int cmp(const void* a, const void* b) { return *(int*)a - *(int*)b; // 升序排序 } int main() { int n; scanf("%d", &n); int t[n]; for (int i = 0; i < n; i++) { scanf("%d", &t[i]); } // 按打水时间升序排序 qsort(t, n, sizeof(int), cmp); long long total_wait = 0; // 总等待时间(可能很大,用long long) int sum = 0; // 前i个人的打水时间之和 for (int i = 0; i < n - 1; i++) { // 最后一个人无人等待 sum += t[i]; total_wait += sum; } // 平均等待时间=总等待时间/人数(题目可能要求整数,直接输出即可) printf("%lld\n", total_wait / n); return 0; }七、总结
蓝桥杯备考没有捷径,但有 “高效路径”—— 3-6 个月按 “基础→进阶→冲刺” 阶段推进,掌握高频考点 + 复用模板 + 实战真题,零基础也能稳步上岸。记住:每天坚持写代码,比 “看 10 道题” 更有用。祝大家都能在蓝桥杯中取得理想成绩!