首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >IO竞赛2025年题目解析:基础级难度(4-5)

IO竞赛2025年题目解析:基础级难度(4-5)

作者头像
安全风信子
发布2025-11-13 13:21:42
发布2025-11-13 13:21:42
2570
举报
文章被收录于专栏:AI SPPECHAI SPPECH

引言

在IO竞赛的学习路径中,基础级难度的题目是连接入门和提高的重要桥梁。2025年的IO竞赛基础级(难度系数4-5)题目开始涉及更多的数据结构和算法思想,对选手的编程能力和逻辑思维提出了更高的要求。本文将详细解析2025年基础级的IO竞赛题目,帮助选手们顺利过渡到更高难度的学习阶段。

代码语言:javascript
复制
难度进阶路径: 入门(1-3) → 基础(4-5) → 提高(6-8) → 竞赛(9-10)

难度系数

考察重点

核心知识点

学习目标

4-5

数据结构、算法应用

栈、队列、树、图的基础应用

掌握基础数据结构的使用和简单算法的实现

目录

代码语言:javascript
复制
目录
├── 第一章:2025年IO竞赛基础级题目概述
├── 第二章:难度系数4题目解析(8题)
├── 第三章:难度系数5题目解析(8题)
├── 第四章:基础级题目解题技巧总结
└── 第五章:从基础到提高的学习建议

第一章:2025年IO竞赛基础级题目概述

根据2025年NOI修订版大纲,基础级(CSP-J提高)的知识点难度系数为4-5,开始涉及更多的数据结构和算法应用。这些题目不仅要求选手掌握基本的编程语法,还需要理解和应用一些基础的数据结构和算法思想。

代码语言:javascript
复制
基础级题目类型分布:
数据结构应用 → 40%
算法设计 → 30%
数学应用 → 20%
综合问题 → 10%

基础级题目的特点:

  • 开始涉及栈、队列、树等基础数据结构
  • 算法复杂度开始成为需要考虑的因素
  • 问题描述更加复杂,需要更深入的分析
  • 对代码的正确性和效率要求更高

第二章:难度系数4题目解析

难度系数4的题目开始考察基础数据结构的应用和简单的算法设计。以下是8道典型的难度系数4题目解析。

2.1 题目1:括号匹配

题目描述:输入一个包含括号的字符串,判断括号是否完全匹配。

解题思路:使用栈来解决括号匹配问题。遍历字符串,遇到左括号则入栈,遇到右括号则检查栈顶元素是否匹配。

C++代码实现

代码语言:javascript
复制
#include <iostream>
#include <stack>
#include <string>
using namespace std;

bool is_valid(string s) {
    stack<char> st;
    for (char c : s) {
        if (c == '(' || c == '[' || c == '{') {
            st.push(c);
        } else {
            if (st.empty()) return false;
            char top = st.top();
            st.pop();
            if ((c == ')' && top != '(') || 
                (c == ']' && top != '[') || 
                (c == '}' && top != '{')) {
                return false;
            }
        }
    }
    return st.empty();
}

int main() {
    string s;
    cin >> s;
    if (is_valid(s)) {
        cout << "Valid" << endl;
    } else {
        cout << "Invalid" << endl;
    }
    return 0;
}
2.2 题目2:滑动窗口最大值

题目描述:给定一个数组和一个窗口大小k,找出所有滑动窗口里的最大值。

解题思路:使用双端队列来维护当前窗口中的最大值。队列中存储的是元素的索引,而非元素值本身。

C++代码实现

代码语言:javascript
复制
#include <iostream>
#include <vector>
#include <deque>
using namespace std;

vector<int> max_sliding_window(vector<int>& nums, int k) {
    vector<int> result;
    deque<int> dq; // 存储索引
    
    for (int i = 0; i < nums.size(); i++) {
        // 移除超出窗口范围的元素
        while (!dq.empty() && dq.front() < i - k + 1) {
            dq.pop_front();
        }
        // 移除比当前元素小的元素
        while (!dq.empty() && nums[dq.back()] < nums[i]) {
            dq.pop_back();
        }
        dq.push_back(i);
        // 当窗口形成时开始记录结果
        if (i >= k - 1) {
            result.push_back(nums[dq.front()]);
        }
    }
    return result;
}

int main() {
    int n, k;
    cin >> n >> k;
    vector<int> nums(n);
    for (int i = 0; i < n; i++) {
        cin >> nums[i];
    }
    vector<int> result = max_sliding_window(nums, k);
    for (int num : result) {
        cout << num << " ";
    }
    cout << endl;
    return 0;
}
2.3 题目3:二叉树的层序遍历

题目描述:给定一棵二叉树,按层序遍历的顺序输出各节点的值。

解题思路:使用队列来实现二叉树的层序遍历。

C++代码实现

代码语言:javascript
复制
#include <iostream>
#include <vector>
#include <queue>
using namespace std;

// 二叉树节点的定义
struct TreeNode {
    int val;
    TreeNode *left;
    TreeNode *right;
    TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};

vector<vector<int>> level_order(TreeNode* root) {
    vector<vector<int>> result;
    if (!root) return result;
    
    queue<TreeNode*> q;
    q.push(root);
    
    while (!q.empty()) {
        int level_size = q.size();
        vector<int> current_level;
        for (int i = 0; i < level_size; i++) {
            TreeNode* node = q.front();
            q.pop();
            current_level.push_back(node->val);
            if (node->left) q.push(node->left);
            if (node->right) q.push(node->right);
        }
        result.push_back(current_level);
    }
    return result;
}

// 构建二叉树(简化版,这里假设输入是按层序遍历的数组,-1表示空节点)
TreeNode* build_tree(vector<int>& nums, int index) {
    if (index >= nums.size() || nums[index] == -1) return NULL;
    TreeNode* root = new TreeNode(nums[index]);
    root->left = build_tree(nums, 2 * index + 1);
    root->right = build_tree(nums, 2 * index + 2);
    return root;
}

int main() {
    int n;
    cin >> n;
    vector<int> nums(n);
    for (int i = 0; i < n; i++) {
        cin >> nums[i];
    }
    TreeNode* root = build_tree(nums, 0);
    vector<vector<int>> result = level_order(root);
    for (auto& level : result) {
        for (int num : level) {
            cout << num << " ";
        }
        cout << endl;
    }
    return 0;
}
2.4 题目4:快速排序

题目描述:实现快速排序算法,对数组进行排序。

解题思路:选择一个基准元素,将数组分为两部分,小于基准的元素放在左边,大于基准的元素放在右边,然后递归地对左右两部分进行排序。

C++代码实现

代码语言:javascript
复制
#include <iostream>
#include <vector>
using namespace std;

int partition(vector<int>& nums, int left, int right) {
    int pivot = nums[right];
    int i = left - 1;
    for (int j = left; j < right; j++) {
        if (nums[j] <= pivot) {
            i++;
            swap(nums[i], nums[j]);
        }
    }
    swap(nums[i + 1], nums[right]);
    return i + 1;
}

void quick_sort(vector<int>& nums, int left, int right) {
    if (left < right) {
        int pivot_index = partition(nums, left, right);
        quick_sort(nums, left, pivot_index - 1);
        quick_sort(nums, pivot_index + 1, right);
    }
}

int main() {
    int n;
    cin >> n;
    vector<int> nums(n);
    for (int i = 0; i < n; i++) {
        cin >> nums[i];
    }
    quick_sort(nums, 0, n - 1);
    for (int num : nums) {
        cout << num << " ";
    }
    cout << endl;
    return 0;
}
2.5 题目5:单链表反转

题目描述:给定一个单链表,将其反转。

解题思路:使用三个指针(前驱、当前、后继)来实现链表的反转。

C++代码实现

代码语言:javascript
复制
#include <iostream>
using namespace std;

// 单链表节点的定义
struct ListNode {
    int val;
    ListNode *next;
    ListNode(int x) : val(x), next(NULL) {}
};

ListNode* reverse_list(ListNode* head) {
    ListNode* prev = NULL;
    ListNode* curr = head;
    while (curr) {
        ListNode* next_temp = curr->next;
        curr->next = prev;
        prev = curr;
        curr = next_temp;
    }
    return prev;
}

// 构建单链表
ListNode* build_list(int n) {
    if (n == 0) return NULL;
    ListNode* head = new ListNode(0);
    ListNode* tail = head;
    for (int i = 0; i < n; i++) {
        int val;
        cin >> val;
        tail->next = new ListNode(val);
        tail = tail->next;
    }
    ListNode* temp = head;
    head = head->next;
    delete temp;
    return head;
}

// 打印链表
void print_list(ListNode* head) {
    while (head) {
        cout << head->val << " ";
        head = head->next;
    }
    cout << endl;
}

int main() {
    int n;
    cin >> n;
    ListNode* head = build_list(n);
    head = reverse_list(head);
    print_list(head);
    return 0;
}
2.6 题目6:二分查找的应用

题目描述:给定一个排序数组和一个目标值,找到目标值在数组中的开始位置和结束位置。

解题思路:使用两次二分查找,分别找到目标值的第一个位置和最后一个位置。

C++代码实现

代码语言:javascript
复制
#include <iostream>
#include <vector>
using namespace std;

vector<int> search_range(vector<int>& nums, int target) {
    vector<int> result = {-1, -1};
    if (nums.empty()) return result;
    
    // 找第一个位置
    int left = 0, right = nums.size() - 1;
    while (left < right) {
        int mid = left + (right - left) / 2;
        if (nums[mid] < target) {
            left = mid + 1;
        } else {
            right = mid;
        }
    }
    if (nums[left] != target) return result;
    result[0] = left;
    
    // 找最后一个位置
    right = nums.size() - 1;
    while (left < right) {
        int mid = left + (right - left + 1) / 2; // 注意这里的向上取整
        if (nums[mid] > target) {
            right = mid - 1;
        } else {
            left = mid;
        }
    }
    result[1] = right;
    return result;
}

int main() {
    int n, target;
    cin >> n >> target;
    vector<int> nums(n);
    for (int i = 0; i < n; i++) {
        cin >> nums[i];
    }
    vector<int> result = search_range(nums, target);
    cout << result[0] << " " << result[1] << endl;
    return 0;
}
2.7 题目7:最小生成树(Kruskal算法)

题目描述:给定一个无向图,使用Kruskal算法找到其最小生成树。

解题思路:Kruskal算法的基本思想是按照边的权值从小到大排序,然后依次选择边,如果加入这条边不会形成环,则将其加入最小生成树。

C++代码实现

代码语言:javascript
复制
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

// 边的定义
struct Edge {
    int u, v, weight;
    Edge(int u, int v, int weight) : u(u), v(v), weight(weight) {}
    bool operator<(const Edge& other) const {
        return weight < other.weight;
    }
};

// 并查集的实现
class UnionFind {
private:
    vector<int> parent;
public:
    UnionFind(int n) {
        parent.resize(n);
        for (int i = 0; i < n; i++) {
            parent[i] = i;
        }
    }
    
    int find(int x) {
        if (parent[x] != x) {
            parent[x] = find(parent[x]);
        }
        return parent[x];
    }
    
    void unite(int x, int y) {
        parent[find(x)] = find(y);
    }
};

int kruskal(vector<Edge>& edges, int n) {
    sort(edges.begin(), edges.end());
    UnionFind uf(n);
    int total_weight = 0;
    int count = 0;
    
    for (const Edge& edge : edges) {
        if (uf.find(edge.u) != uf.find(edge.v)) {
            uf.unite(edge.u, edge.v);
            total_weight += edge.weight;
            count++;
            if (count == n - 1) break; // 最小生成树有n-1条边
        }
    }
    return total_weight;
}

int main() {
    int n, m;
    cin >> n >> m;
    vector<Edge> edges;
    for (int i = 0; i < m; i++) {
        int u, v, weight;
        cin >> u >> v >> weight;
        edges.emplace_back(u, v, weight);
    }
    int min_weight = kruskal(edges, n);
    cout << "最小生成树的总权值:" << min_weight << endl;
    return 0;
}
2.8 题目8:动态规划入门(爬楼梯)

题目描述:假设你正在爬楼梯,需要n阶才能到达楼顶。每次你可以爬1或2个台阶,有多少种不同的方法可以爬到楼顶?

解题思路:这是一个经典的动态规划问题。设dp[i]表示爬到第i阶的不同方法数,则dp[i] = dp[i-1] + dp[i-2]。

C++代码实现

代码语言:javascript
复制
#include <iostream>
#include <vector>
using namespace std;

int climb_stairs(int n) {
    if (n <= 2) return n;
    vector<int> dp(n + 1);
    dp[1] = 1;
    dp[2] = 2;
    for (int i = 3; i <= n; i++) {
        dp[i] = dp[i - 1] + dp[i - 2];
    }
    return dp[n];
}

int main() {
    int n;
    cin >> n;
    cout << climb_stairs(n) << endl;
    return 0;
}

第三章:难度系数5题目解析

难度系数5的题目是基础级中的难题,开始考察更复杂的数据结构应用和算法设计。以下是8道典型的难度系数5题目解析。

3.1 题目1:最短路径(Dijkstra算法)

题目描述:给定一个带权有向图,找出从起点到所有其他顶点的最短路径。

解题思路:使用Dijkstra算法,维护一个优先队列,每次选择当前距离最小的顶点进行松弛操作。

C++代码实现

代码语言:javascript
复制
#include <iostream>
#include <vector>
#include <queue>
#include <climits>
using namespace std;

typedef pair<int, int> pii; // (距离, 顶点)

vector<int> dijkstra(int start, vector<vector<pii>>& graph) {
    int n = graph.size();
    vector<int> dist(n, INT_MAX);
    dist[start] = 0;
    priority_queue<pii, vector<pii>, greater<pii>> pq;
    pq.push({0, start});
    
    while (!pq.empty()) {
        int u = pq.top().second;
        int d = pq.top().first;
        pq.pop();
        
        if (d > dist[u]) continue; // 已经找到更短的路径
        
        for (auto& edge : graph[u]) {
            int v = edge.first;
            int weight = edge.second;
            if (dist[v] > dist[u] + weight) {
                dist[v] = dist[u] + weight;
                pq.push({dist[v], v});
            }
        }
    }
    return dist;
}

int main() {
    int n, m, start;
    cin >> n >> m >> start;
    vector<vector<pii>> graph(n);
    for (int i = 0; i < m; i++) {
        int u, v, weight;
        cin >> u >> v >> weight;
        graph[u].push_back({v, weight});
    }
    vector<int> shortest_dist = dijkstra(start, graph);
    for (int i = 0; i < n; i++) {
        if (shortest_dist[i] == INT_MAX) {
            cout << "INF" << " ";
        } else {
            cout << shortest_dist[i] << " ";
        }
    }
    cout << endl;
    return 0;
}
3.2 题目2:最长递增子序列

题目描述:给定一个数组,找出其中最长的严格递增子序列的长度。

解题思路:使用动态规划的方法,dp[i]表示以第i个元素结尾的最长递增子序列的长度。

C++代码实现

代码语言:javascript
复制
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int length_of_lis(vector<int>& nums) {
    if (nums.empty()) return 0;
    int n = nums.size();
    vector<int> dp(n, 1);
    int max_len = 1;
    
    for (int i = 1; i < n; i++) {
        for (int j = 0; j < i; j++) {
            if (nums[i] > nums[j]) {
                dp[i] = max(dp[i], dp[j] + 1);
            }
        }
        max_len = max(max_len, dp[i]);
    }
    return max_len;
}

int main() {
    int n;
    cin >> n;
    vector<int> nums(n);
    for (int i = 0; i < n; i++) {
        cin >> nums[i];
    }
    cout << length_of_lis(nums) << endl;
    return 0;
}
3.3 题目3:前缀和与差分

题目描述:给定一个数组,多次查询区间和,以及区间更新操作。

解题思路:使用前缀和来快速计算区间和,使用差分数组来高效处理区间更新操作。

C++代码实现

代码语言:javascript
复制
#include <iostream>
#include <vector>
using namespace std;

int main() {
    int n, m;
    cin >> n >> m;
    vector<long long> nums(n + 1);
    vector<long long> prefix_sum(n + 1, 0);
    vector<long long> diff(n + 2, 0); // 差分数组,大小为n+2,避免边界检查
    
    for (int i = 1; i <= n; i++) {
        cin >> nums[i];
        prefix_sum[i] = prefix_sum[i - 1] + nums[i];
    }
    
    while (m--) {
        int op;
        cin >> op;
        if (op == 1) { // 区间查询
            int l, r;
            cin >> l >> r;
            cout << prefix_sum[r] - prefix_sum[l - 1] << endl;
        } else if (op == 2) { // 区间更新
            int l, r, val;
            cin >> l >> r >> val;
            // 更新差分数组
            diff[l] += val;
            diff[r + 1] -= val;
            // 重新计算前缀和
            vector<long long> new_nums(n + 1);
            long long current = 0;
            for (int i = 1; i <= n; i++) {
                current += diff[i];
                new_nums[i] = nums[i] + current;
            }
            // 重新计算前缀和数组
            for (int i = 1; i <= n; i++) {
                prefix_sum[i] = prefix_sum[i - 1] + new_nums[i];
            }
        }
    }
    return 0;
}
3.4 题目4:二叉树的深度

题目描述:给定一棵二叉树,求其最大深度。

解题思路:可以使用递归或迭代的方法来计算二叉树的深度。

C++代码实现

代码语言:javascript
复制
#include <iostream>
#include <vector>
#include <queue>
using namespace std;

// 二叉树节点的定义
struct TreeNode {
    int val;
    TreeNode *left;
    TreeNode *right;
    TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};

// 递归方法
int max_depth_recursive(TreeNode* root) {
    if (!root) return 0;
    int left_depth = max_depth_recursive(root->left);
    int right_depth = max_depth_recursive(root->right);
    return max(left_depth, right_depth) + 1;
}

// 迭代方法(层序遍历)
int max_depth_iterative(TreeNode* root) {
    if (!root) return 0;
    int depth = 0;
    queue<TreeNode*> q;
    q.push(root);
    
    while (!q.empty()) {
        int level_size = q.size();
        depth++;
        for (int i = 0; i < level_size; i++) {
            TreeNode* node = q.front();
            q.pop();
            if (node->left) q.push(node->left);
            if (node->right) q.push(node->right);
        }
    }
    return depth;
}

// 构建二叉树
TreeNode* build_tree(vector<int>& nums, int index) {
    if (index >= nums.size() || nums[index] == -1) return NULL;
    TreeNode* root = new TreeNode(nums[index]);
    root->left = build_tree(nums, 2 * index + 1);
    root->right = build_tree(nums, 2 * index + 2);
    return root;
}

int main() {
    int n;
    cin >> n;
    vector<int> nums(n);
    for (int i = 0; i < n; i++) {
        cin >> nums[i];
    }
    TreeNode* root = build_tree(nums, 0);
    cout << "递归方法:" << max_depth_recursive(root) << endl;
    cout << "迭代方法:" << max_depth_iterative(root) << endl;
    return 0;
}
3.5 题目5:并查集的应用

题目描述:给定一个由n个节点组成的图,初始时每个节点都是孤立的。然后进行m次操作,每次操作可以是合并两个节点所在的集合,或者查询两个节点是否在同一个集合中。

解题思路:使用并查集来高效地处理集合的合并和查询操作。

C++代码实现

代码语言:javascript
复制
#include <iostream>
#include <vector>
using namespace std;

class UnionFind {
private:
    vector<int> parent;
    vector<int> rank; // 用于按秩合并
public:
    UnionFind(int n) {
        parent.resize(n);
        rank.resize(n, 0);
        for (int i = 0; i < n; i++) {
            parent[i] = i;
        }
    }
    
    int find(int x) {
        if (parent[x] != x) {
            parent[x] = find(parent[x]); // 路径压缩
        }
        return parent[x];
    }
    
    void unite(int x, int y) {
        x = find(x);
        y = find(y);
        if (x == y) return;
        // 按秩合并
        if (rank[x] < rank[y]) {
            parent[x] = y;
        } else {
            parent[y] = x;
            if (rank[x] == rank[y]) {
                rank[x]++;
            }
        }
    }
    
    bool is_connected(int x, int y) {
        return find(x) == find(y);
    }
};

int main() {
    int n, m;
    cin >> n >> m;
    UnionFind uf(n);
    
    while (m--) {
        int op, a, b;
        cin >> op >> a >> b;
        if (op == 1) { // 合并
            uf.unite(a, b);
        } else if (op == 2) { // 查询
            if (uf.is_connected(a, b)) {
                cout << "Yes" << endl;
            } else {
                cout << "No" << endl;
            }
        }
    }
    return 0;
}
3.6 题目6:字符串匹配(KMP算法)

题目描述:实现KMP算法,在文本中查找模式串的出现位置。

解题思路:KMP算法的核心是构建部分匹配表(next数组),利用已经匹配过的信息来避免不必要的比较。

C++代码实现

代码语言:javascript
复制
#include <iostream>
#include <string>
#include <vector>
using namespace std;

vector<int> compute_lps(const string& pattern) {
    int m = pattern.size();
    vector<int> lps(m, 0);
    int len = 0; // 前一个状态的LPS值
    int i = 1;
    
    while (i < m) {
        if (pattern[i] == pattern[len]) {
            len++;
            lps[i] = len;
            i++;
        } else {
            if (len != 0) {
                len = lps[len - 1];
            } else {
                lps[i] = 0;
                i++;
            }
        }
    }
    return lps;
}

vector<int> kmp_search(const string& text, const string& pattern) {
    vector<int> result;
    int n = text.size();
    int m = pattern.size();
    if (m == 0) return result;
    
    vector<int> lps = compute_lps(pattern);
    int i = 0; // 文本的索引
    int j = 0; // 模式串的索引
    
    while (i < n) {
        if (pattern[j] == text[i]) {
            i++;
            j++;
        }
        
        if (j == m) {
            result.push_back(i - j);
            j = lps[j - 1];
        } else if (i < n && pattern[j] != text[i]) {
            if (j != 0) {
                j = lps[j - 1];
            } else {
                i++;
            }
        }
    }
    return result;
}

int main() {
    string text, pattern;
    cin >> text >> pattern;
    vector<int> positions = kmp_search(text, pattern);
    if (positions.empty()) {
        cout << "Pattern not found" << endl;
    } else {
        cout << "Pattern found at positions: " << endl;
        for (int pos : positions) {
            cout << pos << " ";
        }
        cout << endl;
    }
    return 0;
}
3.7 题目7:0-1背包问题

题目描述:给定n个物品,每个物品有重量和价值,以及一个容量为C的背包。选择一些物品放入背包,使得总价值最大,且总重量不超过背包容量。

解题思路:使用动态规划的方法,dp[i][j]表示前i个物品中选择一些放入容量为j的背包的最大价值。

C++代码实现

代码语言:javascript
复制
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int knapsack(int capacity, vector<int>& weights, vector<int>& values) {
    int n = weights.size();
    vector<vector<int>> dp(n + 1, vector<int>(capacity + 1, 0));
    
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= capacity; j++) {
            if (weights[i - 1] <= j) {
                // 可以选择放入或者不放入当前物品
                dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weights[i - 1]] + values[i - 1]);
            } else {
                // 不能放入当前物品
                dp[i][j] = dp[i - 1][j];
            }
        }
    }
    return dp[n][capacity];
}

int main() {
    int n, capacity;
    cin >> n >> capacity;
    vector<int> weights(n);
    vector<int> values(n);
    for (int i = 0; i < n; i++) {
        cin >> weights[i] >> values[i];
    }
    cout << knapsack(capacity, weights, values) << endl;
    return 0;
}
3.8 题目8:拓扑排序

题目描述:给定一个有向无环图(DAG),输出其拓扑排序序列。

解题思路:使用Kahn算法进行拓扑排序。首先计算每个节点的入度,然后将入度为0的节点加入队列。每次从队列中取出一个节点,将其加入结果序列,并减少其邻接节点的入度。如果邻接节点的入度变为0,则将其加入队列。

C++代码实现

代码语言:javascript
复制
#include <iostream>
#include <vector>
#include <queue>
using namespace std;

vector<int> topological_sort(int n, vector<vector<int>>& graph) {
    vector<int> in_degree(n, 0);
    for (int u = 0; u < n; u++) {
        for (int v : graph[u]) {
            in_degree[v]++;
        }
    }
    
    queue<int> q;
    for (int i = 0; i < n; i++) {
        if (in_degree[i] == 0) {
            q.push(i);
        }
    }
    
    vector<int> result;
    while (!q.empty()) {
        int u = q.front();
        q.pop();
        result.push_back(u);
        
        for (int v : graph[u]) {
            in_degree[v]--;
            if (in_degree[v] == 0) {
                q.push(v);
            }
        }
    }
    
    // 检查是否存在环
    if (result.size() != n) {
        return {}; // 存在环,返回空数组
    }
    return result;
}

int main() {
    int n, m;
    cin >> n >> m;
    vector<vector<int>> graph(n);
    for (int i = 0; i < m; i++) {
        int u, v;
        cin >> u >> v;
        graph[u].push_back(v);
    }
    vector<int> topo_order = topological_sort(n, graph);
    if (topo_order.empty()) {
        cout << "The graph contains a cycle" << endl;
    } else {
        for (int node : topo_order) {
            cout << node << " ";
        }
        cout << endl;
    }
    return 0;
}

第四章:基础级题目解题技巧总结

通过对2025年IO竞赛基础级题目的解析,我们可以总结出以下解题技巧:

  1. 熟悉数据结构:熟练掌握栈、队列、树、图等基础数据结构的特性和应用场景。
  2. 掌握基础算法:理解并能够实现排序、搜索、动态规划等基础算法。
  3. 分析问题本质:深入理解问题,找到问题的本质,选择合适的算法和数据结构。
  4. 优化时间空间复杂度:在设计算法时,要考虑时间和空间复杂度,选择更高效的算法。
  5. 处理边界条件:仔细考虑各种边界条件和特殊情况。
  6. 代码实现技巧:合理使用语言特性,编写高效、清晰的代码。
代码语言:javascript
复制
解题技巧: 理解问题 → 设计算法 → 分析复杂度 → 编写代码 → 测试调试

第五章:从基础到提高的学习建议

对于已经掌握了基础级知识,想要进一步提高的选手,以下是一些学习建议:

  1. 深入学习算法:系统地学习更高级的算法,如高级动态规划、贪心算法、图论算法等。
  2. 数据结构进阶:学习更复杂的数据结构,如平衡树、线段树、树状数组、字典树等。
  3. 数学知识补充:学习数论、组合数学、概率论等数学知识,这些在高级算法中经常用到。
  4. 多做竞赛题目:通过做竞赛题目来巩固所学的知识,提高解题能力。
  5. 参加模拟比赛:定期参加模拟比赛,适应竞赛环境和节奏。
  6. 学习优秀代码:阅读和学习其他选手的优秀代码,了解不同的解题思路和编程技巧。
代码语言:javascript
复制
进阶学习资源推荐:
- 书籍:《算法竞赛进阶指南》、《算法导论》
- 网站:Codeforces、AtCoder、OI Wiki
- 比赛:NOIP、CSP等竞赛真题

结论

IO竞赛基础级题目的难度适中,主要考察基础数据结构的应用和算法设计能力。通过系统的学习和练习,选手可以逐步掌握解决这些题目的方法和技巧,为进一步学习更高级的知识打下坚实的基础。希望本文的解析能够帮助读者在IO竞赛的道路上取得更好的成绩。

学习价值分布:

代码语言:javascript
复制
数据结构应用(35%) | 算法设计(30%) | 数学基础(20%) | 问题解决能力(15%)

互动讨论:

  1. 在学习基础级算法的过程中,你觉得最难掌握的是哪个部分?为什么?
  2. 对于从入门到基础的过渡,你有什么好的学习方法可以分享?
  3. 在解决基础级题目时,你通常如何选择合适的算法和数据结构?

参考资料

  1. 《算法竞赛进阶指南》- 李煜东
  2. 《算法导论》- Thomas H. Cormen等
  3. 《数据结构与算法分析》- Mark Allen Weiss
  4. OI Wiki - https://oi-wiki.org/
  5. Codeforces - https://codeforces.com/
  6. AtCoder - https://atcoder.jp/
  7. 2025年NOI竞赛大纲
  8. 《C++ Primer》- Stanley B. Lippman等
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-11-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 引言
  • 目录
  • 第一章:2025年IO竞赛基础级题目概述
  • 第二章:难度系数4题目解析
    • 2.1 题目1:括号匹配
    • 2.2 题目2:滑动窗口最大值
    • 2.3 题目3:二叉树的层序遍历
    • 2.4 题目4:快速排序
    • 2.5 题目5:单链表反转
    • 2.6 题目6:二分查找的应用
    • 2.7 题目7:最小生成树(Kruskal算法)
    • 2.8 题目8:动态规划入门(爬楼梯)
  • 第三章:难度系数5题目解析
    • 3.1 题目1:最短路径(Dijkstra算法)
    • 3.2 题目2:最长递增子序列
    • 3.3 题目3:前缀和与差分
    • 3.4 题目4:二叉树的深度
    • 3.5 题目5:并查集的应用
    • 3.6 题目6:字符串匹配(KMP算法)
    • 3.7 题目7:0-1背包问题
    • 3.8 题目8:拓扑排序
  • 第四章:基础级题目解题技巧总结
  • 第五章:从基础到提高的学习建议
  • 结论
  • 参考资料
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档