周娟算法精讲课(C&C++ 版)---789it.top/13828/
备战蓝桥杯:云算法核心模块 C&C++ 版精讲课程
蓝桥杯作为国内最具影响力的IT类赛事之一,其算法竞赛部分对选手的数据结构与算法能力有较高要求。本课程将针对蓝桥杯算法竞赛中的核心模块,使用C/C++语言进行深入讲解,帮助选手高效备战。
一、基础算法模块
1. 排序算法实现
Cpp
// 快速排序模板
void quick_sort(int q[], int l, int r) {
if (l >= r) return;
int i = l - 1, j = r + 1, x = q[l + r >> 1];
while (i < j) {
do i++; while (q[i] < x);
do j--; while (q[j] > x);
if (i < j) swap(q[i], q[j]);
}
quick_sort(q, l, j), quick_sort(q, j + 1, r);
}
// 归并排序模板
void merge_sort(int q[], int l, int r) {
if (l >= r) return;
int mid = l + r >> 1;
merge_sort(q, l, mid), merge_sort(q, mid + 1, r);
int k = 0, i = l, j = mid + 1;
while (i <= mid && j <= r)
if (q[i] <= q[j]) tmp[k++] = q[i++];
else tmp[k++] = q[j++];
while (i <= mid) tmp[k++] = q[i++];
while (j <= r) tmp[k++] = q[j++];
for (i = l, j = 0; i <= r; i++, j++) q[i] = tmp[j];
}
2. 二分查找算法
Cpp
// 整数二分模板
int binary_search(int l, int r) {
while (l < r) {
int mid = l + r >> 1;
if (check(mid)) r = mid;
else l = mid + 1;
}
return l;
}
// 浮点数二分模板
double binary_search(double l, double r) {
const double eps = 1e-6;
while (r - l > eps) {
double mid = (l + r) / 2;
if (check(mid)) r = mid;
else l = mid;
}
return l;
}
二、数据结构模块
1. 线性数据结构
Cpp
// 单调栈实现
vector<int> nextGreaterElement(vector<int>& nums) {
vector<int> res(nums.size());
stack<int> s;
for (int i = nums.size() - 1; i >= 0; i--) {
while (!s.empty() && s.top() <= nums[i]) s.pop();
res[i] = s.empty() ? -1 : s.top();
s.push(nums[i]);
}
return res;
}
// 单调队列实现滑动窗口最大值
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
vector<int> res;
deque<int> q;
for (int i = 0; i < nums.size(); i++) {
if (!q.empty() && q.front() == i - k) q.pop_front();
while (!q.empty() && nums[q.back()] <= nums[i]) q.pop_back();
q.push_back(i);
if (i >= k - 1) res.push_back(nums[q.front()]);
}
return res;
}
2. 树状数组与线段树
Cpp
// 树状数组模板
class FenwickTree {
private:
vector<int> tree;
public:
FenwickTree(int n) : tree(n + 1) {}
void update(int i, int delta) {
while (i < tree.size()) {
tree[i] += delta;
i += i & -i;
}
}
int query(int i) {
int sum = 0;
while (i > 0) {
sum += tree[i];
i -= i & -i;
}
return sum;
}
};
// 线段树模板(区间求和)
class SegmentTree {
private:
vector<int> tree;
int n;
public:
SegmentTree(vector<int>& nums) {
n = nums.size();
tree.resize(2 * n);
for (int i = n; i < 2 * n; i++) tree[i] = nums[i - n];
for (int i = n - 1; i > 0; i--) tree[i] = tree[2 * i] + tree[2 * i + 1];
}
void update(int pos, int val) {
pos += n;
tree[pos] = val;
while (pos > 1) {
pos >>= 1;
tree[pos] = tree[2 * pos] + tree[2 * pos + 1];
}
}
int query(int l, int r) {
l += n;
r += n;
int sum = 0;
while (l <= r) {
if (l % 2 == 1) sum += tree[l++];
if (r % 2 == 0) sum += tree[r--];
l >>= 1;
r >>= 1;
}
return sum;
}
};
三、图论模块
1. 图的存储与遍历
Cpp
// 邻接表存储图
vector<vector<int>> adj;
// DFS遍历
void dfs(int u, vector<bool>& visited) {
visited[u] = true;
for (int v : adj[u]) {
if (!visited[v]) dfs(v, visited);
}
}
// BFS遍历
void bfs(int start) {
queue<int> q;
vector<bool> visited(adj.size(), false);
q.push(start);
visited[start] = true;
while (!q.empty()) {
int u = q.front();
q.pop();
for (int v : adj[u]) {
if (!visited[v]) {
visited[v] = true;
q.push(v);
}
}
}
}
2. 最短路径算法
Cpp
// Dijkstra算法(邻接矩阵版)
void dijkstra(int graph[V][V], int src) {
int dist[V];
bool sptSet[V];
for (int i = 0; i < V; i++) dist[i] = INT_MAX, sptSet[i] = false;
dist[src] = 0;
for (int count = 0; count < V - 1; count++) {
int u = minDistance(dist, sptSet);
sptSet[u] = true;
for (int v = 0; v < V; v++)
if (!sptSet[v] && graph[u][v] && dist[u] != INT_MAX
&& dist[u] + graph[u][v] < dist[v])
dist[v] = dist[u] + graph[u][v];
}
}
// Floyd算法(动态规划)
void floyd(int graph[V][V]) {
int dist[V][V];
for (int i = 0; i < V; i++)
for (int j = 0; j < V; j++)
dist[i][j] = graph[i][j];
for (int k = 0; k < V; k++)
for (int i = 0; i < V; i++)
for (int j = 0; j < V; j++)
if (dist[i][k] + dist[k][j] < dist[i][j])
dist[i][j] = dist[i][k] + dist[k][j];
}
四、动态规划模块
1. 经典DP问题
Cpp
// 0-1背包问题
int knapsack(int W, vector<int>& wt, vector<int>& val, int n) {
vector<vector<int>> dp(n + 1, vector<int>(W + 1));
for (int i = 1; i <= n; i++) {
for (int w = 1; w <= W; w++) {
if (wt[i - 1] <= w)
dp[i][w] = max(val[i - 1] + dp[i - 1][w - wt[i - 1]], dp[i - 1][w]);
else
dp[i][w] = dp[i - 1][w];
}
}
return dp[n][W];
}
// 最长公共子序列
int lcs(string X, string Y, int m, int n) {
vector<vector<int>> dp(m + 1, vector<int>(n + 1));
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
if (X[i - 1] == Y[j - 1])
dp[i][j] = dp[i - 1][j - 1] + 1;
else
dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
}
}
return dp[m][n];
}
2. 数位DP
Cpp
// 数字1的个数统计
int countDigitOne(int n) {
int count = 0;
for (long long i = 1; i <= n; i *= 10) {
long long divider = i * 10;
count += (n / divider) * i + min(max(n % divider - i + 1, 0LL), i);
}
return count;
}
// 数位DP模板(记忆化搜索)
int dp[20][2][2];
vector<int> digits;
int dfs(int pos, bool tight, bool lead, int state) {
if (pos == digits.size()) return 1;
if (dp[pos][tight][lead] != -1) return dp[pos][tight][lead];
int limit = tight ? digits[pos] : 9;
int res = 0;
for (int d = 0; d <= limit; d++) {
bool newTight = tight && (d == limit);
bool newLead = lead && (d == 0);
// 根据题目要求添加状态转移条件
res += dfs(pos + 1, newTight, newLead, state);
}
return dp[pos][tight][lead] = res;
}
int digitDP(int num) {
memset(dp, -1, sizeof(dp));
digits.clear();
while (num) {
digits.push_back(num % 10);
num /= 10;
}
reverse(digits.begin(), digits.end());
return dfs(0, true, true, 0);
}
五、比赛技巧与策略
-
输入输出优化
Cpp
// C++ IO加速 ios::sync_with_stdio(false); cin.tie(nullptr); // 快速读取整数 int read() { int x = 0, f = 1; char ch = getchar(); while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); } while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); } return x * f; } -
常用STL容器与方法
Cpp
// 优先队列自定义比较 auto cmp = [](int a, int b) { return a > b; }; priority_queue<int, vector<int>, decltype(cmp)> pq(cmp); // 自定义排序 sort(v.begin(), v.end(), [](const auto& a, const auto& b) { return a.second < b.second; }); -
调试技巧
Cpp
// 调试宏定义 #define debug(x) cerr << #x << " = " << x << endl #define debug2(x, y) cerr << #x << " = " << x << ", " << #y << " = " << y << endl // 随机数生成 mt19937 rng(chrono::steady_clock::now().time_since_epoch().count()); int rand_int(int l, int r) { return uniform_int_distribution<int>(l, r)(rng); }
六、蓝桥杯备赛建议
-
刷题策略
- 按照算法模块系统练习
- 重点突破历年真题
- 针对薄弱环节专项训练
-
时间管理
- 简单题快速解决(15分钟内)
- 中等题合理分配时间(30-45分钟)
- 难题先写部分分再尝试优化
-
资源推荐
- 蓝桥杯官方练习系统
- LeetCode、Codeforces等在线平台
- 《算法竞赛入门经典》等经典教材
-
模拟训练
- 定期进行全真模拟赛
- 分析错题和未完成题目
- 总结常见错误和优化方法
通过系统学习这些核心算法模块,掌握C/C++的高效实现方式,结合科学的备赛策略,相信你一定能在蓝桥杯算法竞赛中取得优异成绩!