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

Part04 算法

CSP-J 初赛常考知识点总结 - 算法篇

1. 算法概念与描述

1.1 算法概念

  • 算法:解决特定问题的有限步骤序列
  • 特性:有穷性、确定性、可行性、输入、输出
  • 评价标准:时间复杂度、空间复杂度、正确性、可读性

1.2 算法描述

  • 自然语言描述:用人类语言描述算法步骤
  • 流程图描述:使用标准图形符号表示算法流程
  • 伪代码描述:介于自然语言和编程语言之间的描述方式

1.3 流程图符号含义

开始/结束
输入/输出
处理/操作
判断/分支
流程方向
连接点
圆角矩形
平行四边形
矩形
菱形
箭头
圆形

标准流程图符号含义:

  • 圆角矩形:开始/结束符号
  • 平行四边形:输入/输出操作
  • 矩形:处理步骤/普通操作
  • 菱形:判断/决策步骤
  • 箭头:流程方向
  • 圆形:连接点(用于连接不同页的流程图)

2. 入门算法

2.1 枚举法

  • 思想:遍历所有可能的情况,找到满足条件的解
  • 适用场景:解空间有限的问题
  • 时间复杂度:通常为 O(n)O(n)O(n)O(n2)O(n^2)O(n2)
// 示例:找出100以内的所有质数
for (int i = 2; i <= 100; i++) {bool isPrime = true;for (int j = 2; j * j <= i; j++) {if (i % j == 0) {isPrime = false;break;}}if (isPrime) cout << i << " ";
}

2.2 模拟法

  • 思想:按照题目要求直接模拟过程
  • 适用场景:流程清晰、步骤明确的问题
  • 关键:准确理解题意,注意边界条件

3. 基础算法

3.1 贪心法

  • 思想:每一步都采取当前最优选择
  • 特点:局部最优不一定导致全局最优
  • 适用条件:最优子结构、贪心选择性质
部分背包问题(经典例题)

问题描述:有 nnn 个物品,第 iii 个物品重量为 w[i]w[i]w[i],价值为 v[i]v[i]v[i]。背包容量为 CCC,如何选择物品放入背包,使得总价值最大?(物品可以分割)

贪心策略:按单位重量价值( vw\frac{v}{w}wv )从大到小排序,优先选择单位价值高的物品。

struct node {double m, v; // 重量m和价值vdouble avg;  // 性价比(价值/重量)
} a[1010];
bool cmp(node a, node b) { return a.avg > b.avg; }
int main() { // 主程序入口int N, T;double sum = 0;cin >> N >> T;for (int i = 1; i <= N; i++) {cin >> a[i].m >> a[i].v;a[i].avg = a[i].v / a[i].m;}sort(a + 1, a + 1 + N, cmp);for (int i = 1; i <= N; i++) {if (a[i].m <= T) { // 最多能够取得(减去)当前物品的重量sum += a[i].v;T -= a[i].m; // 剩余的背包容量 = 当前背包容量 -// 能最装当前物品i的(最多)重量} else {sum += T * a[i].avg;break;}}printf("%.2lf", sum);return 0;
}

3.2 递推法

  • 思想:根据已知条件逐步推导出后续结果
  • 公式f(n)=F(f(n−1),f(n−2),…)f(n) = F(f(n-1), f(n-2), \ldots)f(n)=F(f(n1),f(n2),)
  • 典型应用:斐波那契数列、杨辉三角
// 斐波那契数列递推
int fib(int n) {if (n <= 1) return n;int f0 = 0, f1 = 1, f2;for (int i = 2; i <= n; i++) {f2 = f0 + f1;f0 = f1;f1 = f2;}return f1;
}

3.3 递归法

  • 思想:函数调用自身来解决问题
  • 要素:递归基、递归关系
  • 优缺点:代码简洁,但可能栈溢出
// 递归实现阶乘
int factorial(int n) {if (n == 0 || n == 1) retur n 1; // 递归基return n * factorial(n - 1);    // 递归关系
}

3.4 二分法

  • 思想:在有序序列中每次排除一半的搜索空间
  • 时间复杂度O(log⁡n)O(\log n)O(logn)
  • 应用:二分查找、二分答案
// 二分查找模板
int binarySearch(int arr[], int n, int target) {int left = 0, right = n - 1;while (left <= right) {int mid = left + (right - left) / 2;if (arr[mid] == target) return mid;else if (arr[mid] < target) left = mid + 1;else right = mid - 1;}return -1;
}

3.5 倍增法

  • 思想:通过倍增加速处理过程
  • 应用:快速幂、ST表、LCA
// 快速幂算法
long long fastPow(long long a, long long b) {long long result = 1;while (b) {if (b & 1) result *= a;a *= a;b >>= 1;}return result;
}

4. 数值处理算法

4.1 高精度加法

void add(int a[], int b[], int c[], int len) {int carry = 0;for (int i = 0; i < len; i++) {int sum = a[i] + b[i] + carry;c[i] = sum % 10;carry = sum / 10;}if (carry > 0) {c[len] = carry;}
}

4.2 高精度减法

void sub(int a[], int b[], int c[], int len) {int borrow = 0;for (int i = 0; i < len; i++) {int diff = a[i] - b[i] - borrow;if (diff < 0) {diff += 10;borrow = 1;} else {borrow = 0;}c[i] = diff;}
}

4.3 高精度乘法

void mul(int a[], int b, int c[], int len) {int carry = 0;for (int i = 0; i < len; i++) {int product = a[i] * b + carry;c[i] = product % 10;carry = product / 10;}if (carry > 0) {c[len] = carry;}
}

4.4 高精度除法(高除低)

void div(int a[], int b, int c[], int &r, int len) {r = 0;for (int i = len - 1; i >= 0; i--) {int dividend = r * 10 + a[i];c[i] = dividend / b;r = dividend % b;}
}

5. 排序算法

5.1 排序算法总结

排序算法最好时间复杂度平均时间复杂度最坏时间复杂度空间复杂度稳定性适用场景
冒泡排序O(n)O(n)O(n)O(n2)O(n^2)O(n2)O(n2)O(n^2)O(n2)O(1)O(1)O(1)稳定小规模数据
选择排序O(n2)O(n^2)O(n2)O(n2)O(n^2)O(n2)O(n2)O(n^2)O(n2)O(1)O(1)O(1)不稳定小规模数据
插入排序O(n)O(n)O(n)O(n2)O(n^2)O(n2)O(n2)O(n^2)O(n2)O(1)O(1)O(1)稳定小规模或基本有序数据
计数排序O(n+k)O(n+k)O(n+k)O(n+k)O(n+k)O(n+k)O(n+k)O(n+k)O(n+k)O(k)O(k)O(k)稳定数据范围小的整数排序
快速排序O(nlog⁡n)O(n \log n)O(nlogn)O(nlog⁡n)O(n \log n)O(nlogn)O(n2)O(n^2)O(n2)O(log⁡n)O(\log n)O(logn)不稳定大规模数据,平均性能好
归并排序O(nlog⁡n)O(n \log n)O(nlogn)O(nlog⁡n)O(n \log n)O(nlogn)O(nlog⁡n)O(n \log n)O(nlogn)O(n)O(n)O(n)稳定大规模数据,稳定排序
堆排序O(nlog⁡n)O(n \log n)O(nlogn)O(nlog⁡n)O(n \log n)O(nlogn)O(nlog⁡n)O(n \log n)O(nlogn)O(1)O(1)O(1)不稳定大规模数据,原地排序

5.2 冒泡排序

void bubbleSort(int arr[], int n) {for (int i = 0; i < n - 1; i++)for (int j = 0; j < n - i - 1; j++)if (arr[j] > arr[j + 1]) {int temp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = temp;}
}

5.3 选择排序

void selectionSort(int arr[], int n) {for (int i = 0; i < n - 1; i++) {int minIndex = i;for (int j = i + 1; j < n; j++)if (arr[j] < arr[minIndex])minIndex = j;int temp = arr[i];arr[i] = arr[minIndex];arr[minIndex] = temp;}
}

5.4 插入排序

void insertionSort(int arr[], int n) {for (int i = 1; i < n; i++) {int key = arr[i];int j = i - 1;while (j >= 0 && arr[j] > key) {arr[j + 1] = arr[j];j--;}arr[j + 1] = key;}
}

5.5 计数排序

void countingSort(int arr[], int n) {// 找出最大值int maxVal = arr[0];for (int i = 1; i < n; i++)if (arr[i] > maxVal)maxVal = arr[i];// 创建计数数组int count[maxVal + 1];for (int i = 0; i <= maxVal; i++)count[i] = 0;// 计数for (int i = 0; i < n; i++)count[arr[i]]++;// 重建数组int index = 0;for (int i = 0; i <= maxVal; i++)while (count[i] > 0) {arr[index++] = i;count[i]--;}
}

6. 搜索算法

6.1 深度优先搜索 (DFS)

// 使用邻接矩阵表示的图
void dfs(int node, bool visited[], int graph[][MAX], int n) {visited[node] = true;printf("%d ", node);for (int i = 0; i < n; i++) {if (graph[node][i] == 1 && !visited[i]) {dfs(i, visited, graph, n);}}
}

6.2 广度优先搜索 (BFS)

// 使用邻接矩阵表示的图
void bfs(int start, bool visited[], int graph[][MAX], int n) {int queue[MAX];int front = 0, rear = 0;visited[start] = true;queue[rear++] = start;while (front < rear) {int node = queue[front++];printf("%d ", node);for (int i = 0; i < n; i++)if (graph[node][i] == 1 && !visited[i]) {visited[i] = true;queue[rear++] = i;}}
}

7. 图论算法

7.1 深度优先遍历

  • 应用:连通分量检测、拓扑排序、环路检测

7.2 广度优先遍历

  • 应用:最短路径(无权图)、连通性检测

7.3 泛洪算法-洪水填充 (Flood Fill)

// 使用二维数组表示的图像
void floodFill(int image[][MAX], int sr, int sc, int newColor, int oldColor, int m, int n) {if (sr < 0 || sr >= m || sc < 0 || sc >= n || image[sr][sc] != oldColor) return;image[sr][sc] = newColor;// 四个方向递归填充floodFill(image, sr + 1, sc, newColor, oldColor, m, n);floodFill(image, sr - 1, sc, newColor, oldColor, m, n);floodFill(image, sr, sc + 1, newColor, oldColor, m, n);floodFill(image, sr, sc - 1, newColor, oldColor, m, n);
}

8. 动态规划

8.1 基本思路

  1. 定义状态dp[i]dp[i]dp[i] 表示什么含义
  2. 状态转移方程dp[i]=F(dp[i−1],dp[i−2],…)dp[i] = F(dp[i-1], dp[i-2], \ldots)dp[i]=F(dp[i1],dp[i2],)
  3. 初始化:基础情况的处理
  4. 计算顺序:确定计算方向
  5. 结果提取:从状态中获取最终答案

8.2 简单一维动态规划

// 斐波那契数列
int fib(int n) {if (n <= 1)return n;int dp[n + 1];dp[0] = 0, dp[1] = 1;for (int i = 2; i <= n; i++)dp[i] = dp[i - 1] + dp[i - 2];return dp[n];
}

8.3 0-1背包问题

// f[j]:背包容量为 j,可选择前 i 件物品的最大价值
for (int i = 1; i <= n; i++)for (int j = m; j >= w[i]; i--)f[j] = max(f[j], f[j - w[i]] + v[i]);

8.4 完全背包问题

// f[i][j]:可选择前 i 个物品,重量为 j 的最大价值
for (int i = 1; i <= n; i++)for (int j = w[i]; j <= m; i++)f[i][j] = max(f[i][j], f[i][j - w[i]] + v[i]);

8.5 最长上升子序列 (LIS)

const int N = 5005;
// f[i]:所有的 (1~i) 子序列中含 i 为结尾的上升子序列最长长度
int f[N], a[N], n;
int main() {cin >> n;for (int i = 1; i <= n; i++)cin >> a[i], f[i] = 1;for (int i = 1; i <= n; i++)for (int j = 1; j < i; j++)if (a[j] < a[i])f[i] = max(f[i], f[j] + 1);int ans = 0;for (int i = 1; i <= n; i++)ans = max(ans, f[i]);cout << ans << "\n";
}

8.6 简单区间动态规划

for (int len = 1; len <= n; len++)       // 枚举:区间长度for (int i = 1; i + len <= n; i++) { // 枚举:左端点int j = i + len;                 // 计算右端点for (int k = i; k < j; k++)      //  枚举:分割点dp[i][j] = max / min(dp[i][j], dp[i][k] + dp[k][j]);}

9. STL 部分应用

9.1 优先队列 (priority_queue)

#include <queue>
#include <functional>// 默认是大顶堆
priority_queue<int> maxHeap;// 小顶堆的声明方式
priority_queue<int, vector<int>, greater<int>> minHeap;// 基本操作
maxHeap.push(3);    // 插入元素
maxHeap.push(1);
maxHeap.push(4);
maxHeap.push(1);
maxHeap.push(5);cout << maxHeap.top(); // 5 (获取最大元素)
maxHeap.pop();         // 删除最大元素
cout << maxHeap.top(); // 4// 自定义比较函数
struct Compare {bool operator()(int a, int b) {return a > b; // 小顶堆}
};
priority_queue<int, vector<int>, Compare> customHeap;

9.2 一维前缀和与差分

前缀和
// 预处理前缀和数组
void precomputePrefixSum(int arr[], int n, int prefix[]) {prefix[0] = arr[0];for (int i = 1; i < n; i++) {prefix[i] = prefix[i - 1] + arr[i];}
}// 查询区间和 [l, r]
int queryRangeSum(int prefix[], int l, int r) {if (l == 0) return prefix[r];return prefix[r] - prefix[l - 1];
}
差分
// 构建差分数组
void buildDifferenceArray(int arr[], int n, int diff[]) {diff[0] = arr[0];for (int i = 1; i < n; i++) {diff[i] = arr[i] - arr[i - 1];}
}// 区间修改 [l, r] 增加 val
void rangeUpdate(int diff[], int n, int l, int r, int val) {diff[l] += val;if (r + 1 < n) {diff[r + 1] -= val;}
}// 从差分数组还原原数组
void restoreArray(int diff[], int n, int arr[]) {arr[0] = diff[0];for (int i = 1; i < n; i++) {arr[i] = arr[i - 1] + diff[i];}
}

9.3 STL 二分查找函数

#include <algorithm>
#include <vector>vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};// lower_bound: 返回第一个大于等于目标值的迭代器
auto lb = lower_bound(v.begin(), v.end(), 5);
cout << "lower_bound for 5 at position " << (lb - v.begin()) << endl;// upper_bound: 返回第一个大于目标值的迭代器
auto ub = upper_bound(v.begin(), v.end(), 5);
cout << "upper_bound for 5 at position " << (ub - v.begin()) << endl;// binary_search: 检查元素是否存在
bool exists = binary_search(v.begin(), v.end(), 5);// 在普通数组中使用
int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int n = sizeof(arr) / sizeof(arr[0]);int* lb_arr = lower_bound(arr, arr + n, 5);
cout << "lower_bound for 5 at position " << (lb_arr - arr) << endl;

备考建议

  1. 理解各种算法的基本思想和适用场景
  2. 掌握常见算法的模板代码
  3. 熟练分析算法的时间复杂度和空间复杂度
  4. 多练习经典算法问题,提高解决问题的能力
  5. 注意算法在实际应用中的优化技巧

常见考点

  • 排序算法的选择和实现
  • 搜索算法的应用和优化
  • 动态规划的状态设计和转移方程
  • 图论算法的基本操作和应用
  • 高精度运算的实现和处理

CSP-J 入门组复习大纲

  • 2.1.1 基础知识与编程环境
  • 2.1.2 C++ 程序设计
  • 2.1.3 数据结构
  • 2.1.4 算法
  • 2.1.5 数学
  • 2.1.6 其他杂项

文章转载自:

http://olZqU9Ac.mLpch.cn
http://hmFkNo5v.mLpch.cn
http://FtfU18tT.mLpch.cn
http://6fQOaYh9.mLpch.cn
http://YfWyoEHi.mLpch.cn
http://VAYBSrZq.mLpch.cn
http://4eqG0oi1.mLpch.cn
http://eCLvR4Sq.mLpch.cn
http://O1dFKDWq.mLpch.cn
http://FzsqCvuA.mLpch.cn
http://1paorVob.mLpch.cn
http://fmDlLJnc.mLpch.cn
http://GItqTgTt.mLpch.cn
http://pppZVzSr.mLpch.cn
http://zQoI9nB8.mLpch.cn
http://tbfWgPqQ.mLpch.cn
http://2hsLVkdB.mLpch.cn
http://7ZeA6C6j.mLpch.cn
http://BrBkXzvI.mLpch.cn
http://csYjlSvz.mLpch.cn
http://r4ArW7iI.mLpch.cn
http://g0eQRZlt.mLpch.cn
http://buIOoJEe.mLpch.cn
http://rrcbAvqS.mLpch.cn
http://fkBi6NQW.mLpch.cn
http://pdigUYaq.mLpch.cn
http://VEtpR8je.mLpch.cn
http://xHffuYgH.mLpch.cn
http://ePqYmyWq.mLpch.cn
http://C9jQX9G6.mLpch.cn
http://www.dtcms.com/a/388310.html

相关文章:

  • 硬件 - 立创EDA入门实践 - 从DCDC降压芯片带您从原理图到PCB到打板
  • 安全认证哪家强?CISP和HCIE我选......
  • 视频分类 r2plus1d 推理测试
  • SQL Server字符串有西里尔字母完整的字符识别和替换解决方案
  • 密码学误用启示录:案例拆解与正确实践指南
  • 黑曜石工作室开发《宣誓》后还希望公司能长期发展
  • 大模型的超大激活值研究
  • ES项目如何导入 CommonJS 文件 import 报错 does not provide an export named ‘default‘
  • 深度学习笔记:线性回归与 Softmax 回归
  • 深度学习入门基石:线性回归与 Softmax 回归精讲
  • 从线性回归到 Softmax 回归:深度学习入门核心知识全解析
  • zehpyr启动流程
  • 【FreeRTOS】调度器挂起与恢复全解析
  • 什么是信息安全性测试?如何选择第三方检测机构?
  • SSM框架——Spring、SpingMVC、Mybatis
  • MongoDB+cpolar:跨环境数据库管理的无缝方案
  • Java 泛型详解:从基础到实践
  • Python与GDAL库进行遥感图像处理:一个完整的实战教程
  • 构建AI智能体:三十六、决策树的核心机制(二):抽丝剥茧简化专业术语推理最佳分裂点
  • computeIfAbsent用法讲解
  • freertos代码结构
  • C++底层刨析章节一:STL概述与设计哲学:深入理解C++标准模板库的核心
  • 多态的原理与实现机制
  • [C++]异常
  • Windows PE 文件结构详解:从入口到执行的旅程
  • LLM 处理 PDF 表格的最佳方法:从解析到高效利用
  • 自动驾驶中的传感器技术50——Radar(11)
  • WALL-OSS--自变量机器人--2025.9.8--开源
  • GJOI 9.11/9.13 题解
  • 基于Spark的用户实时分析