周娟算法精讲课(C&C++ 版)

116 阅读5分钟

周娟算法精讲课(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);
}

五、比赛技巧与策略

  1. 输入输出优化

    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;
    }
    
  2. 常用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;
    });
    
  3. 调试技巧

    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); }
    

六、蓝桥杯备赛建议

  1. 刷题策略

    • 按照算法模块系统练习
    • 重点突破历年真题
    • 针对薄弱环节专项训练
  2. 时间管理

    • 简单题快速解决(15分钟内)
    • 中等题合理分配时间(30-45分钟)
    • 难题先写部分分再尝试优化
  3. 资源推荐

    • 蓝桥杯官方练习系统
    • LeetCode、Codeforces等在线平台
    • 《算法竞赛入门经典》等经典教材
  4. 模拟训练

    • 定期进行全真模拟赛
    • 分析错题和未完成题目
    • 总结常见错误和优化方法

通过系统学习这些核心算法模块,掌握C/C++的高效实现方式,结合科学的备赛策略,相信你一定能在蓝桥杯算法竞赛中取得优异成绩!