当前位置: 首页 > news >正文

CSP 复赛入门组高频算法:典型例题、代码模板与实战题号

CSP 复赛入门组高频算法:典型例题、代码模板与实战题号

说明

本文档按 CSP 复赛入门组核心知识点分类,包含 “核心思路 + 典型例题 + 代码模板 + 实战题号”,覆盖考试高频考点,适用于教师教学与学生自主复习,所有代码均通过语法验证,实战题号来自洛谷、力扣、一本通等权威平台。

一、基础运算与枚举

1. 核心思路

通过循环遍历所有可能情况,直接按题目要求模拟流程或验证条件,是入门组最基础且必拿分的题型,重点考查代码逻辑的严谨性。

2. 典型例题

  • 模拟类:按题目给定步骤实现操作(如日期计算、计算器模拟)
  • 枚举类:在指定范围遍历,筛选符合条件的解(如寻找指定区间内的质数)

3. 代码模板(日期计算:判断某日期是当年第几天)

 
#include <iostream>using namespace std;// 判断是否为闰年bool isLeap(int year) {return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);}int main() {int year, month, day;cin >> year >> month >> day;// 非闰年和闰年的月份天数(索引0对应1月,索引1对应2月)int daysInMonth[] = {31,28,31,30,31,30,31,31,30,31,30,31};if (isLeap(year)) daysInMonth[1] = 29; // 闰年2月29天int sum = 0;// 累加前面月份的总天数for (int i = 0; i < month - 1; i++) {sum += daysInMonth[i];}sum += day; // 加当月天数cout << sum << endl;return 0;}

4. 实战题号(点击链接直达题目)

  • 洛谷:P1014 [NOIP1999 普及组] Cantor 表(模拟规律遍历)
  • 洛谷:P1157 组合的输出(枚举组合情况)
  • 一本通:1165:亲和数(枚举因数求和)

二、简单数学

1. 核心思路

利用数学公式或定理简化计算,避免暴力枚举的低效,常见于数论、区间计算类题目,重点掌握基础公式的应用场景。

2. 典型例题

  • 最大公约数(GCD):求两数最大公约数,是 LCM、因数相关题目的基础
  • 快速幂:高效计算 \(a^b \mod m\)(适用于指数极大的场景)
  • 前缀和:快速计算数组区间和,降低时间复杂度(从 O (n) 优化到 O (1))

3. 代码模板

(1)GCD(欧几里得算法)
 
#include <iostream>using namespace std;// 递归实现欧几里得算法int gcd(int a, int b) {return b == 0 ? a : gcd(b, a % b); // 核心公式:gcd(a,b) = gcd(b, a%b)}int main() {int a, b;cin >> a >> b;cout << "最大公约数:" << gcd(a, b) << endl;// 最小公倍数(LCM)= 两数乘积 / 最大公约数(需注意先乘后除可能溢出,此处适用于入门组数据范围)cout << "最小公倍数:" << a * b / gcd(a, b) << endl;return 0;}
(2)快速幂(计算 \(a^b \mod m\))
 
#include <iostream>using namespace std;// 非递归实现快速幂,避免栈溢出long long quickPow(long long a, long long b, long long mod) {long long res = 1; // 结果初始化为1(任何数的0次幂为1)while (b > 0) {if (b % 2 == 1) { // 若当前二进制位为1,乘上对应权重a^(2^k)res = (res * a) % mod;}a = (a * a) % mod; // a自乘,权重翻倍(a^1 → a^2 → a^4 → ...)b /= 2; // 二进制右移一位,处理下一位}return res;}int main() {long long a, b, mod;cin >> a >> b >> mod;cout << a << "^" << b << " mod " << mod << " = " << quickPow(a, b, mod) << endl;return 0;}
(3)前缀和(一维数组区间和查询)
 
#include <iostream>using namespace std;const int N = 1005; // 数组最大长度(根据题目需求调整)int arr[N]; // 原数组int preSum[N]; // 前缀和数组:preSum[i] = arr[1] + arr[2] + ... + arr[i]int main() {int n, q; // n:数组元素个数;q:查询次数cin >> n >> q;for (int i = 1; i <= n; i++) { // 前缀和数组通常从索引1开始,避免边界判断cin >> arr[i];preSum[i] = preSum[i - 1] + arr[i]; // 递推公式}// 处理q次区间和查询(每次查询[l, r]的和)while (q--) {int l, r;cin >> l >> r;// 区间和 = 前r项和 - 前l-1项和cout << "区间[" << l << "," << r << "]的和:" << preSum[r] - preSum[l - 1] << endl;}return 0;}

4. 实战题号

  • 洛谷:P1029 [NOIP2001 普及组] 最大公约数和最小公倍数问题(GCD 与 LCM 综合应用)
  • 洛谷:P1226 【模板】快速幂(快速幂模板题,熟悉边界处理)
  • 洛谷:P3406 海底高铁(前缀和思想解决区间计数问题)
  • 力扣:303. 区域和检索 - 数组不可变(前缀和基础应用题)

三、排序与查找

1. 核心思路

  • 排序:将数据按规则整理,为后续操作(如二分查找、统计)铺路,入门组重点掌握sort函数的使用
  • 二分查找:在有序数据中高效定位目标(时间复杂度 O (logn)),适用于 “查找目标值”“寻找满足条件的最值” 等场景

2. 典型例题

  • 排序应用:排序后解决 “第 k 大 / 小数”“相邻元素差值最大值” 等问题
  • 二分查找:有序数组中找目标、木材切割(找最大切割长度)、银行贷款(找最小利率)等

3. 代码模板

(1)排序(基于 C++ STL 的 sort 函数)
 
#include <iostream>#include <algorithm> // sort函数所在头文件using namespace std;// 自定义排序规则:从大到小(默认是从小到大)bool cmp(int a, int b) {return a > b;}int main() {int arr[] = {3, 1, 4, 2, 5};int n = sizeof(arr) / sizeof(arr[0]); // 计算数组长度// 1. 从小到大排序(默认规则)sort(arr, arr + n);cout << "从小到大排序:";for (int i = 0; i < n; i++) cout << arr[i] << " ";cout << endl;// 2. 从大到小排序(传入自定义cmp函数)sort(arr, arr + n, cmp);cout << "从大到小排序:";for (int i = 0; i < n; i++) cout << arr[i] << " ";cout << endl;// 例题:找第2大的数(排序后直接取索引1)cout << "第2大的数:" << arr[1] << endl;return 0;}
(2)二分查找(有序数组中找目标值)
 
#include <iostream>#include <algorithm> // binary_search函数所在头文件using namespace std;int main() {int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};int n = sizeof(arr) / sizeof(arr[0]);int target = 5; // 目标值// 方法1:手写二分查找(可获取目标索引)int left = 0, right = n - 1;bool found = false;int targetIndex = -1;while (left <= right) {// 计算中间索引(避免left+right溢出,等价于(left+right)/2)int mid = left + (right - left) / 2;if (arr[mid] == target) {found = true;targetIndex = mid;break;} else if (arr[mid] < target) {left = mid + 1; // 目标在右半段} else {right = mid - 1; // 目标在左半段}}if (found) {cout << "手写二分:找到目标" << target << ",索引为" << targetIndex << endl;} else {cout << "手写二分:未找到目标" << target << endl;}// 方法2:使用STL的binary_search(仅判断是否存在,返回bool)if (binary_search(arr, arr + n, target)) {cout << "STL binary_search:找到目标" << target << endl;} else {cout << "STL binary_search:未找到目标" << target << endl;}return 0;}

4. 实战题号

  • 洛谷:P1177 【模板】排序(sort 函数综合应用,处理不同数据类型)
  • 洛谷:P1163 银行贷款(二分查找解决 “满足条件的最小值” 问题)
  • 力扣:35. 搜索插入位置(二分查找基础应用题,找插入位置)
  • 一本通:1319:【例 6.1】排队接水(排序后计算最优解,贪心思想结合排序)

四、动态规划入门

1. 核心思路

将复杂问题分解为多个重叠子问题,通过存储子问题的解(定义 “状态”),避免重复计算,核心是确定 “状态定义” 和 “状态转移方程”,入门组重点掌握 1 维 DP 和简单 2 维 DP。

2. 典型例题

  • 1 维 DP:最长上升子序列(LIS)、斐波那契数列优化(避免递归重复计算)
  • 2 维 DP:01 背包(每件物品选或不选,求背包最大价值)

3. 代码模板

(1)最长上升子序列(LIS,O (n²) 复杂度,适用于入门组数据范围)
 
#include <iostream>#include <algorithm>using namespace std;const int N = 1005;int arr[N]; // 原数组int dp[N]; // dp[i]:以第i个元素结尾的最长上升子序列长度int main() {int n;cin >> n;for (int i = 1; i <= n; i++) {cin >> arr[i];dp[i] = 1; // 初始状态:每个元素自身是长度为1的子序列}int maxLen = 1; // 记录最长上升子序列的长度for (int i = 2; i <= n; i++) {// 遍历i之前的所有元素j,若arr[j] < arr[i],则dp[i]可由dp[j]+1更新for (int j = 1; j < i; j++) {if (arr[j] < arr[i]) {dp[i] = max(dp[i], dp[j] + 1);}}maxLen = max(maxLen, dp[i]); // 更新最长长度}cout << "最长上升子序列长度:" << maxLen << endl;return 0;}
(2)01 背包(空间优化版,O (nv) 时间复杂度,O (v) 空间复杂度)
 
#include <iostream>using namespace std;const int N = 1005; // 物品最大数量const int V = 1005; // 背包最大容量int weight[N]; // 物品重量int value[N]; // 物品价值int dp[V]; // dp[v]:容量为v的背包能装的最大价值int main() {int n, v; // n:物品数量;v:背包容量cin >> n >> v;for (int i = 1; i <= n; i++) {cin >> weight[i] >> value[i];}// 01背包核心:倒序遍历容量,避免同一物品被重复选择for (int i = 1; i <= n; i++) {// j从v倒序到weight[i],确保每个物品只选一次for (int j = v; j >= weight[i]; j--) {// 状态转移:选第i件物品(dp[j-weight[i]]+value[i]) vs 不选(dp[j])dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);}}cout << "背包最大价值:" << dp[v] << endl;return 0;}

4. 实战题号

  • 洛谷:P1020 [NOIP1999 普及组] 导弹拦截(LIS 变形题,经典必做,理解 “最长不升子序列”)
  • 洛谷:P1048 [NOIP2005 普及组] 采药(01 背包模板题,数据范围适合入门组)
  • 力扣:322. 零钱兑换(DP 入门应用题,完全背包变形,理解 “最小硬币数” 状态定义)
  • 一本通:1267:【例 9.11】01 背包问题(01 背包基础实战,熟悉二维 DP 与空间优化)

五、图论基础(DFS 与 BFS)

1. 核心思路

  • DFS(深度优先搜索):以 “一条路走到黑” 的方式遍历,通过递归或栈实现,优先探索当前节点的邻接节点,直到无法前进再回溯。适合解决连通块计数所有路径查找迷宫回溯等问题,重点在于 “回溯” 与 “标记已访问节点”,避免重复遍历。
  • BFS(广度优先搜索):以 “逐层扩散” 的方式遍历,通过队列实现,先访问当前节点的所有邻接节点,再依次访问邻接节点的邻接节点。适合解决无权图最短路径(如迷宫最短步数)、层序遍历最短转换路径等问题,核心是 “队列缓存待访问节点”,确保按距离从近到远遍历。

2. 典型例题

  • DFS 场景:统计二维网格中的岛屿数量(连通块)、寻找迷宫中所有从起点到终点的路径。
  • BFS 场景:计算迷宫从起点到终点的最少移动步数、马在棋盘上从起点到终点的最少跳数。

3. 代码模板

(1)DFS(二维网格连通块计数,以 “统计岛屿数量” 为例)
 
#include <iostream>using namespace std;const int N = 105; // 网格最大尺寸(根据题目需求调整)int grid[N][N]; // 网格:1表示陆地(岛屿),0表示水域bool visited[N][N];// 标记数组:true表示已访问,避免重复遍历// 方向数组:上下左右四个方向(x为行,y为列)int dir[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};int n, m; // n:网格行数,m:网格列数// DFS函数:遍历以(x,y)为起点的连通块,并标记所有访问过的陆地void dfs(int x, int y) {visited[x][y] = true; // 标记当前节点为已访问// 遍历四个方向的邻接节点for (int i = 0; i < 4; i++) {int nx = x + dir[i][0]; // 新节点的行坐标int ny = y + dir[i][1]; // 新节点的列坐标// 检查新节点是否合法:1.在网格范围内 2.未被访问 3.是陆地(grid=1)if (nx >= 1 && nx <= n && ny >= 1 && ny <= m&& !visited[nx][ny] && grid[nx][ny] == 1) {dfs(nx, ny); // 递归遍历邻接陆地}}}int main() {cin >> n >> m;// 输入网格数据(注意:若题目中网格以0开始索引,需调整循环边界)for (int i = 1; i <= n; i++) {for (int j = 1; j <= m; j++) {cin >> grid[i][j];}}int islandCount = 0; // 统计岛屿数量// 遍历网格的每个节点for (int i = 1; i <= n; i++) {for (int j = 1; j <= m; j++) {// 若当前节点是未访问的陆地,说明找到一个新岛屿if (!visited[i][j] && grid[i][j] == 1) {dfs(i, j); // 遍历该岛屿的所有陆地islandCount++; // 岛屿数量+1}}}cout << "岛屿数量:" << islandCount << endl;return 0;}
(2)BFS(二维迷宫最短步数,以 “从起点到终点的最少移动次数” 为例)
 
#include <iostream>#include <queue> // BFS需使用队列存储待访问节点using namespace std;const int N = 105;int grid[N][N]; // 网格:0表示可走,1表示障碍bool visited[N][N];// 标记数组:避免重复入队int dir[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};int n, m;// 定义节点结构体:存储坐标(x,y)和从起点到该节点的步数struct Node {int x; // 行坐标int y; // 列坐标int step; // 步数};// BFS函数:计算从起点(sx,sy)到终点(ex,ey)的最少步数,无法到达返回-1int bfs(int sx, int sy, int ex, int ey) {// 初始化队列,将起点入队queue<Node> q;q.push({sx, sy, 0});visited[sx][sy] = true; // 标记起点为已访问// 遍历队列中的所有节点while (!q.empty()) {Node curr = q.front(); // 取出队首节点(当前节点)q.pop(); // 弹出队首节点// 若当前节点是终点,直接返回步数(BFS确保首次到达为最短路径)if (curr.x == ex && curr.y == ey) {return curr.step;}// 遍历四个方向的邻接节点for (int i = 0; i < 4; i++) {int nx = curr.x + dir[i][0];int ny = curr.y + dir[i][1];// 检查新节点是否合法:1.在网格范围内 2.未被访问 3.不是障碍(grid=0)if (nx >= 1 && nx <= n && ny >= 1 && ny <= m&& !visited[nx][ny] && grid[nx][ny] == 0) {visited[nx][ny] = true; // 标记为已访问(避免重复入队)q.push({nx, ny, curr.step + 1}); // 步数+1后入队}}}// 队列遍历结束仍未找到终点,说明无法到达return -1;}int main() {int sx, sy, ex, ey; // 起点(sx,sy),终点(ex,ey)cin >> n >> m;// 输入网格数据for (int i = 1; i <= n; i++) {for (int j = 1; j <= m; j++) {cin >> grid[i][j];}}// 输入起点和终点坐标(注意:需与网格索引规则一致,此处为1-based)cin >> sx >> sy >> ex >> ey;// 调用BFS计算最短步数int minStep = bfs(sx, sy, ex, ey);if (minStep == -1) {cout << "无法从起点到达终点" << endl;} else {cout << "从起点到终点的最少步数:" << minStep << endl;}return 0;}

4. 实战题号(点击链接直达题目,难度匹配入门组)

  • DFS 类题目
    • 洛谷:P1605 迷宫(经典 DFS 迷宫题,需处理 “禁止回头” 和 “路径标记”)
    • 力扣:200. 岛屿数量(与代码模板场景一致,连通块计数基础题)
    • 一本通:1251:仙岛求药(DFS + 回溯,寻找迷宫中的目标物品)
  • BFS 类题目
    • 洛谷:P1443 马的遍历(棋盘 BFS,计算马到每个格子的最少跳数,需扩展方向数组)
    • 洛谷:P5461 赦免战俘(BFS + 递归,适合理解 “逐层处理” 思想)
    • 力扣:1091. 二进制矩阵中的最短路径(迷宫最短路径,方向数组扩展为 8 个方向)
    • 一本通:1240:奥运奖牌计数(BFS 入门题,统计连通块内的元素和)

5. 教学与复习建议

  • DFS 重点:让学生理解 “递归回溯” 的逻辑,尤其是 “标记已访问” 和 “回溯时取消标记” 的区别(如路径查找需取消标记,连通块计数无需取消)。
  • BFS 重点:强调 “队列的作用” 和 “首次到达即最短路径” 的特性,避免学生混淆 BFS 与 DFS 的适用场景(如求最短路径优先用 BFS,求所有路径优先用 DFS)。
  • 实战技巧:让学生先独立实现模板代码,再尝试修改题目中的 “网格规则”(如方向数、障碍定义),逐步适应不同场景的变化。

关于本文中,如有需要详解讲解的请私信,希望能帮助到更多有需要的人,各位加油。

http://www.dtcms.com/a/435742.html

相关文章:

  • 做网站需要哪些准备工作心得体会简短的
  • 基础建设文本网站阿里云1M做网站
  • 江苏建设工程信息网站网站的设计页面
  • 网站建设工作基本流程做二手网站赚钱不
  • 嵌入式学习笔记5.定时器TIM
  • 博达高校网站群建设教程家在临深业主论坛家在深圳
  • 两学一做网站网站网站开发前端库
  • 模型轻量化三大核心技术之:蒸馏
  • 备案关闭网站建设影响淮南最新通告今天
  • 购物网站怎么建立门户类网站模板
  • 昭通微网站建设wordpress 只显示标题
  • 数据结构从入门到实战————队列
  • 微信二维码网站制作固原网络推广
  • 丢弃法-Dropout
  • 1.多线程基础概念
  • 队列queue
  • 网站平台规划最便宜的网站叫什么名字
  • 【Java】从入门到放弃-05:高级语法
  • 全国十大网站建设公司wordpress mp6
  • 责任链与规则树设计实战解析(自用)
  • 网站建设太金手指六六二九代理产品网
  • 栾城做网站云南信息发布平台
  • DrissionPage爬取汽车之家:(车名 + 颜色 + 车辆型号/续航里程)
  • 360做企业网站多少钱淘宝客网站怎么做的
  • 网站制作课程介绍清远网站制作公司
  • 宁志网站两学一做匀贵网站建设
  • 树莓派点亮LED灯
  • 如何解决 pip install -r requirements.txt 安装报错 递归包含:文件通过 -r 引用了自身 问题
  • 【实证分析】A股上市公司权益资本成本数据-基于MPEG模型(2001-2024年)
  • 制作公司工作网站网站数据库是干什么的