408ds中的c++简单实现

kmp

#include <iostream>
#include <vector>
#include <string>

using namespace std;

// 计算 pattern 的 next 数组
vector<int> get_next(string pattern) {
    int n = pattern.length();
    vector<int> next(n + 1); // 初始化 next 数组
    next[0] = -1; // 初始化 next[0] 为 -1
    int i = 0, j = -1;
    while (i < n) { // 遍历 pattern,计算 next 数组
        if (j == -1 || pattern[i] == pattern[j]) { // 如果 j == -1 或者当前字符匹配成功
            ++i; // i 和 j 同时向后移动
            ++j;
            next[i] = j; // 更新 next[i]
        } else {
            j = next[j]; // 如果匹配失败,j 回溯到上一个相同的字符位置
        }
    }
    return next; // 返回 next 数组
}

// 计算 pattern 的 nextval 数组
vector<int> get_nextval(string pattern) {
    int n = pattern.length();
    vector<int> next;
    next = get_next(pattern); // 先求出 pattern 的 next 数组
    vector<int> nextval(n + 1); // 初始化 nextval 数组
    nextval[0] = -1; // 初始化 nextval[0] 为 -1
    for (int i = 1; i <= n; ++i) { // 遍历 pattern,计算 nextval 数组
        if (pattern[i] == pattern[next[i]]) { // 如果有多个相同的前缀
            nextval[i] = nextval[next[i]]; // 直接用 nextval[next[i]] 的值
        } else {
            nextval[i] = next[i]; // 否则使用 next[i] 的值
        }
    }
    return nextval; // 返回 nextval 数组
}

// KMP 算法
vector<int> kmp(string text, string pattern) {
    int n = text.length(), m = pattern.length();
    vector<int> next, res;
    next = get_next(pattern); // 求出 pattern 的 next 数组
    int i = 0, j = 0;
    while (i < n) {
        if (j == -1 || text[i] == pattern[j]) { // 如果 j == -1 或者当前字符匹配成功
            ++i; // i 和 j 同时向后移动
            ++j;
        } else {
            j = next[j]; // 如果匹配失败,j 回溯到上一个相同的字符位置
        }
        if (j == m) { // 如果匹配成功
            res.push_back(i - m); // 把当前的起始位置加入结果数组
            j = next[j]; // 回溯到上一个相同的字符位置,继续匹配
        }
    }
    return res; // 返回所有匹配的起始位置
}


// luogu P3375
int main() {
    string text, pattern;
    cin >> text >> pattern;
    vector<int> next, nextval, res;
    next = get_next(pattern);
    nextval = get_nextval(pattern);
    res = kmp(text, pattern);
    for (auto u : res) {
        cout << u + 1 << endl;
    }
    for (int i = 1; i <= pattern.length(); i++) {
        cout << next[i] << ' ';
    }
    cout << endl;
    return 0;
}

先序、中序建二叉树

#include <iostream>
#include <vector>
#include <stack>
#include <unordered_map>

using namespace std;

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

/*
// 从前序和中序遍历序列构造二叉树
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
    // 构建中序遍历元素值和索引的哈希表,方便快速查找元素在中序遍历中的位置
    unordered_map<int, int> map;
    for (int i = 0; i < inorder.size(); ++i) {
        map[inorder[i]] = i;
    }

    // 递归构建二叉树
    return buildTreeHelper(preorder, inorder, map, 0, preorder.size() - 1, 0, inorder.size() - 1);
}

// 递归构建二叉树的辅助函数
TreeNode* buildTreeHelper(vector<int>& preorder, vector<int>& inorder, unordered_map<int, int>& map, int preStart, int preEnd, int inStart, int inEnd) {
    // 递归终止条件:前序遍历序列为空
    if (preStart > preEnd) {
        return nullptr;
    }

    // 构建根节点
    int rootVal = preorder[preStart];
    TreeNode* root = new TreeNode(rootVal);

    // 根据中序遍历序列划分左右子树
    int rootIndex = map[rootVal];
    int leftSize = rootIndex - inStart;
    int rightSize = inEnd - rootIndex;

    // 递归构建左子树和右子树
    root->left = buildTreeHelper(preorder, inorder, map, preStart + 1, preStart + leftSize, inStart, rootIndex - 1);
    root->right = buildTreeHelper(preorder, inorder, map, preStart + leftSize + 1, preEnd, rootIndex + 1, inEnd);

    return root;
}
*/

TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
    // 如果前序遍历序列为空,则返回空指针
    if (!preorder.size()) {
        return nullptr;
    }
    // 构造根节点
    TreeNode* root = new TreeNode(preorder[0]);
    // 用栈来维护构造过程
    stack<TreeNode*> stk;
    // 将根节点入栈
    stk.push(root);
    // 记录中序遍历序列的当前位置
    int inorderIndex = 0;
    // 从前序遍历序列的第二个元素开始构造二叉树
    for (int i = 1; i < preorder.size(); ++i) {
        // 获取当前要构造的节点值
        int preorderVal = preorder[i];
        // 获取栈顶节点
        TreeNode* node = stk.top();
        // 如果栈顶节点不等于当前中序遍历序列的元素
        if (node->val != inorder[inorderIndex]) {
            // 则当前节点作为栈顶节点的左子节点
            node->left = new TreeNode(preorderVal);
            // 将当前节点入栈
            stk.push(node->left);
        } else {
            // 否则,从栈中取出根节点到当前节点的所有节点,它们的值都小于当前中序遍历序列的元素
            while (!stk.empty() && stk.top()->val == inorder[inorderIndex]) {
                node = stk.top();
                stk.pop();
                ++inorderIndex;
            }
            // 在最后一个取出的节点上添加右子节点
            node->right = new TreeNode(preorderVal);
            // 将右子节点入栈
            stk.push(node->right);
        }
    }
    // 返回根节点
    return root;
}

// 打印二叉树的中序遍历序列
void inorderTraversal(TreeNode* root) {
    if (root == nullptr) {
        return;
    }
    inorderTraversal(root->left);
    cout << root->val << " ";
    inorderTraversal(root->right);
}

void preorderTraversal(TreeNode* root) {
    if (root == nullptr) {
        return;
    }
    cout << root->val << " ";
    preorderTraversal(root->left);
    preorderTraversal(root->right);
}


void postorderTraversal(TreeNode* root) {
    if (root == nullptr) {
        return;
    }
    postorderTraversal(root->left);
    postorderTraversal(root->right);
    cout << root->val << " ";
}

// Leetcode 105
int main() {
    // 测试样例
    vector<int> preorder = { 1, 2, 4, 6, 7, 3, 5 };
    vector<int> inorder = { 2, 6, 4, 7, 1, 5, 3 };
    TreeNode* root = buildTree(preorder, inorder);

    preorderTraversal(root);
    cout << endl;

    inorderTraversal(root);
    cout << endl;

    postorderTraversal(root);
    cout << endl;
    return 0;
}

后序、中序建二叉树

#include <iostream>
#include <vector>
#include <stack>

using namespace std;

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

/*
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
    return build(inorder, postorder, 0, inorder.size() - 1, 0, postorder.size() - 1);
}

TreeNode* build(vector<int>& inorder, vector<int>& postorder, int inStart, int inEnd, int postStart, int postEnd) {
    if (inStart > inEnd || postStart > postEnd) {
        return nullptr;
    }

    // 后序遍历的最后一个元素是根节点
    int rootVal = postorder[postEnd];
    TreeNode* root = new TreeNode(rootVal);

    // 找到根节点在中序遍历序列中的位置
    int rootIndex;
    for (int i = inStart; i <= inEnd; ++i) {
        if (inorder[i] == rootVal) {
            rootIndex = i;
            break;
        }
    }

    // 递归构造左子树和右子树
    int leftSize = rootIndex - inStart;
    root->left = build(inorder, postorder, inStart, rootIndex - 1, postStart, postStart + leftSize - 1);
    root->right = build(inorder, postorder, rootIndex + 1, inEnd, postStart + leftSize, postEnd - 1);

    return root;
}
*/

TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
    // 如果后序遍历序列为空,则返回空指针
    if (postorder.size() == 0) {
        return nullptr;
    }
    // 构造根节点
    auto root = new TreeNode(postorder[postorder.size() - 1]);
    // 用栈来维护构造过程
    auto s = stack<TreeNode*>();
    // 将根节点入栈
    s.push(root);
    // 记录中序遍历序列的当前位置
    int inorderIndex = inorder.size() - 1;
    // 从后序遍历序列的倒数第二个元素开始构造二叉树
    for (int i = int(postorder.size()) - 2; i >= 0; i--) {
        // 获取当前要构造的节点值
        int postorderVal = postorder[i];
        // 获取栈顶节点
        auto node = s.top();
        // 如果栈顶节点不等于当前中序遍历序列的元素
        if (node->val != inorder[inorderIndex]) {
            // 则当前节点作为栈顶节点的右子节点
            node->right = new TreeNode(postorderVal);
            // 将当前节点入栈
            s.push(node->right);
        } else {
            // 否则,从栈中取出根节点到当前节点的所有节点,它们的值都大于当前中序遍历序列的元素
            while (!s.empty() && s.top()->val == inorder[inorderIndex]) {
                node = s.top();
                s.pop();
                inorderIndex--;
            }
            // 在最后一个取出的节点上添加左子节点
            node->left = new TreeNode(postorderVal);
            // 将左子节点入栈
            s.push(node->left);
        }
    }
    // 返回根节点
    return root;
}

void inorderTraversal(TreeNode* root) {
    if (root == nullptr) {
        return;
    }
    inorderTraversal(root->left);
    cout << root->val << " ";
    inorderTraversal(root->right);
}

void preorderTraversal(TreeNode* root) {
    if (root == nullptr) {
        return;
    }
    cout << root->val << " ";
    preorderTraversal(root->left);
    preorderTraversal(root->right);
}


void postorderTraversal(TreeNode* root) {
    if (root == nullptr) {
        return;
    }
    postorderTraversal(root->left);
    postorderTraversal(root->right);
    cout << root->val << " ";
}

// Leetcode 106
int main() {
    // 测试样例
    vector<int> postorder = { 6, 7, 4, 2, 5, 3, 1 };
    vector<int> inorder = { 2, 6, 4, 7, 1, 5, 3 };
    TreeNode* root = buildTree(inorder, postorder);

    preorderTraversal(root);
    cout << endl;

    inorderTraversal(root);
    cout << endl;

    postorderTraversal(root);
    cout << endl;
    return 0;
}

并查集

#include <iostream>
#include <cstring>

using namespace std;

const int N = 1e5 + 10;

int s[N]; // 并查集数组,其中 s[x] < 0 表示 x 是根节点,其绝对值表示集合的大小

void init() {
    memset(s, -1, sizeof(s)); // 初始化并查集数组,全部置为 -1
}

// 查找 x 所在的集合的根节点
/*
int find(int x) {
    if (s[x] < 0) return x;
    return s[x] = find(s[x]);
}
*/

int find(int x) {
    int rt = x;
    while (s[rt] >= 0) {
        rt = s[rt];
    }
    while (x != rt) {
        int t = s[x];
        s[x] = rt;
        x = t;
    }
    return rt;
}

// 将 x 和 y 所在的集合合并
bool unite(int x, int y) {
    x = find(x);
    y = find(y);
    if (x == y) return false; // x 和 y 已经在同一集合中,无需合并
    if (s[x] < s[y]) {
        s[x] += s[y]; // 将 y 集合并入 x 集合
        s[y] = x;
    } else {
        s[y] += s[x]; // 将 x 集合并入 y 集合
        s[x] = y;
    }
    return true; // 合并成功
}

// luogu P3367
int main() {
    int n, m;
    cin >> n >> m;
    init();
    int x, y, z;
    for (int i = 0; i < m; i++) {
        cin >> z >> x >> y;
        cout << find(x) << ' ' << find(y) << endl;
        if (z == 2) {
            if (find(x) == find(y)) {
                cout << 'Y' << endl;
            } else {
                cout << 'N' << endl;
            }
        } else {
            unite(x, y);
        }
    }
    return 0;
}

bfs

#include <iostream>
#include <queue>
#include <vector>

using namespace std;

const int MAXN = 10010;

vector<int> G[MAXN]; // 邻接表存储图
bool vis[MAXN]; // 记录节点是否已经访问过

void bfs(int start) {
    queue<int> q; // 队列存储待访问的节点
    q.push(start); // 入队起始节点
    vis[start] = true; // 标记起始节点已访问
    while (!q.empty()) {
        int cur = q.front(); // 取出队首节点
        q.pop();
        // 对当前节点cur进行操作
        cout << cur << " ";
        // 将cur的邻接节点入队
        for (int i = 0; i < G[cur].size(); i++) {
            int v = G[cur][i];
            if (!vis[v]) {
                q.push(v);
                vis[v] = true;
            }
        }
    }
}

int main() {
    int n, m;
    cin >> n >> m; // 输入节点数和边数
    for (int i = 0; i < m; i++) {
        int u, v;
        cin >> u >> v; // 输入一条边
        G[u].push_back(v);
        G[v].push_back(u); // 无向图需要加入反向边
    }
    bfs(1); // 从1号节点开始BFS遍历
    return 0;
}

dfs

#include <iostream>
#include <unordered_set>
#include <vector>

using namespace std;

const int MAXN = 10010;

// 定义邻接表存储图的结构
vector<int> G[MAXN];
// 定义用于记录是否已经访问过节点的unordered_set
unordered_set<int> vis;

// 深度优先遍历函数,从节点u开始遍历
void dfs(int u) {
    // 标记节点u已经被访问过
    vis.insert(u);
    // 输出节点u的编号
    cout << u << ' ';
    // 遍历节点u的邻接节点
    for (auto v : G[u]) {
        // 如果邻接节点v还没有被访问过,就从v开始继续遍历
        if (!vis.count(v)) {
            dfs(v);
        }
    }
}

int main() {
    int n, m;
    cin >> n >> m; // 输入节点数和边数
    for (int i = 0; i < m; i++) {
        int u, v;
        cin >> u >> v; // 输入一条边
        G[u].push_back(v);
        G[v].push_back(u); // 无向图需要加入反向边
    }
    dfs(1); // 从1号节点开始BFS遍历
    return 0;
}

prim

#include <iostream>
#include <vector>
#include <queue>
#include <cstring>

using namespace std;

const int MAXN = 1e5 + 5;

struct Edge {
    int v, w; // 边的终点和权值
    Edge(int _v, int _w): v(_v), w(_w) {}
    bool operator<(const Edge& e) const { // 重载运算符以实现小根堆
        return w > e.w;
    }
};

vector<Edge> G[MAXN]; // 邻接表存储图
bool vis[MAXN]; // 标记是否在最小生成树中
int dist[MAXN]; // 记录点到最小生成树的距离

int prim(int s) {
    memset(dist, 0x3f, sizeof(dist)); // 初始化所有点到最小生成树距离为无穷大
    priority_queue<Edge> q; // 定义一个小根堆
    q.push(Edge(s, 0)); // 将起点加入小根堆
    dist[s] = 0;
    int res = 0; // 最小生成树的总权值
    while (!q.empty()) {
        int u = q.top().v; // 取出小根堆中距离最小的点
        q.pop();
        if (vis[u]) continue; // 如果该点已经在最小生成树中,则跳过
        vis[u] = true;
        res += dist[u]; // 将该点加入最小生成树
        for (auto e : G[u]) { // 遍历与该点相邻的边
            int v = e.v, w = e.w;
            if (!vis[v] && dist[v] > w) { // 如果该点未在最小生成树中且距离比当前最短路径更短,则更新距离并加入小根堆
                dist[v] = w;
                q.push(Edge(v, w));
            }
        }
    }
    return res;
}

// Luogu P3366
int main() {
    int n, m;
    cin >> n >> m;
    int x, y, z;
    for (int i = 0; i < m; i++) {
        cin >> x >> y >> z;
        G[x].push_back({ y, z });
        G[y].push_back({ x, z });
    }
    int ans = prim(1);
    for (int i = 1; i <= n; i++) {
        if (!vis[i]) {
            cout << "orz" << endl;
            return 0;
        }
    }
    cout << ans << endl;
}

kruskal

#include <iostream>
#include <algorithm>
#include <vector>

using namespace std;

const int MAXN = 1e5 + 5;

struct Edge {
    int u, v, w;
    Edge(int _u, int _v, int _w): u(_u), v(_v), w(_w) {}
    bool operator<(const Edge& e) const {
        return w < e.w;
    }
};

int n, m;
int fa[MAXN];

// 初始化并查集
void init() {
    for (int i = 1; i <= n; i++) {
        fa[i] = i;
    }
}

// 并查集查找根节点
int find(int x) {
    if (fa[x] != x) {
        fa[x] = find(fa[x]);
    }
    return fa[x];
}

// Kruskal 算法求最小生成树,返回最小生成树的边权之和
int kruskal(vector<Edge>& edges) {
    init();
    int res = 0, cnt = 0;
    sort(edges.begin(), edges.end()); // 将所有边按边权从小到大排序
    for (auto& e : edges) {
        int u = e.u, v = e.v, w = e.w;
        int x = find(u), y = find(v);
        if (x == y) continue; // 如果 u 和 v 已在同一集合中,则跳过该边
        fa[x] = y; // 否则将 u 所在集合合并到 v 所在集合中
        res += w; // 计算最小生成树边权之和
        cnt++; // 统计最小生成树的边数
        if (cnt == n - 1) break; // 如果边数达到 n-1,则生成树已经构建完成
    }
    return res;
}

// Luogu P3366
int main() {
    cin >> n >> m;
    vector<Edge> edges; // 存储所有边
    for (int i = 0; i < m; i++) {
        int u, v, w;
        cin >> u >> v >> w;
        edges.push_back(Edge(u, v, w)); // 将边加入 vector 中
    }
    int res = kruskal(edges); // 求最小生成树
    for (int i = 1; i <= n; i++) {
        if (find(i) != find(1)) {
            cout << "orz" << endl;
            return 0;
        }
    }
    cout << res << endl;
    return 0;
}

dijkstra

#include <iostream>
#include <vector>
#include <queue>
#include <cstring>

using namespace std;

const int MAXN = 1e5 + 5; // 最大点数
const int INF = 0x3f3f3f3f; // 无穷大

struct Edge {
    int v, w;
    Edge(int _v, int _w): v(_v), w(_w) {}
};

vector<Edge> G[MAXN]; // 邻接表存储图
bool vis[MAXN]; // 标记是否已确定最短路
int dist[MAXN]; // 记录起点到各点的最短路

void dijkstra(int s) {
    memset(dist, 0x3f, sizeof(dist)); // 初始化起点到各点距离为无穷大
    priority_queue<pair<int, int>, vector<pair<int, int>>, greater<>> q;
    // pair中第一项表示距离,第二项表示点的编号
    q.push({ 0, s });
    dist[s] = 0;
    while (!q.empty()) {
        int u = q.top().second;
        q.pop();
        if (vis[u]) continue;
        vis[u] = true;
        for (auto e : G[u]) {
            int v = e.v, w = e.w;
            if (dist[v] > dist[u] + w) {
                dist[v] = dist[u] + w;
                q.push({ dist[v], v });
            }
        }
    }
}


// Luogu P3371 P4779
int main() {
    int n, m, s;
    cin >> n >> m >> s; // n表示点数,m表示边数,s表示起点
    for (int i = 0; i < m; i++) {
        int u, v, w;
        cin >> u >> v >> w;
        G[u].push_back(Edge(v, w));
    }
    dijkstra(s);
    for (int i = 1; i <= n; i++) {
        if (dist[i] == INF) cout << (1 << 31) - 1 << ' '; // 无法到达
        else cout << dist[i] << ' ';
    }
    cout << endl;
    return 0;
}

floyd

#include <iostream>
#include <cstring>

using namespace std;

const int INF = 0x3f3f3f3f;
const int MAXN = 1005;

int d[MAXN][MAXN]; // 记录所有点对之间的最短路径
int n, m;

void floyd() {
    for (int k = 1; k <= n; k++) {
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= n; j++) {
                d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
            }
        }
    }
}

// NC14697
int main() {
    int D;
    cin >> n >> m >> D;

    // 初始化距离矩阵,注意自己到自己的距离为0
    memset(d, 0x3f, sizeof(d));
    for (int i = 1; i <= n; i++) {
        d[i][i] = 0;
    }

    // 读入边权
    for (int i = 1; i <= m; i++) {
        int a, b, w;
        cin >> a >> b >> w;
        d[a][b] = min(d[a][b], w);
    }

    floyd();

    int ans = 0;

    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) {
            if (d[i][j] == D) ans++;
        }
    }
    cout << ans << endl;
    return 0;
}

topo

#include <iostream>
#include <vector>
#include <queue>

using namespace std;

const int N = 1e5 + 5;

vector<int> G[N]; // 邻接表存储图
int in_degree[N]; // 记录每个点的入度

vector<int> topo_sort(int n) {
    vector<int> res; // 记录排序结果
    queue<int> q; // 存储入度为0的点
    for (int i = 1; i <= n; i++) {
        if (in_degree[i] == 0) q.push(i); // 将入度为0的点加入队列中
    }
    while (!q.empty()) {
        int u = q.front();
        q.pop();
        res.push_back(u);
        for (auto v : G[u]) {
            in_degree[v]--; // 减去当前点的出边,相当于将它的邻居节点入度减一
            if (in_degree[v] == 0) q.push(v); // 如果相邻节点的入度变成了0,加入队列中
        }
    }
    return res;
}

int main() {
    int n, m;
    cin >> n >> m;
    for (int i = 0; i < m; i++) {
        int u, v;
        cin >> u >> v;
        G[u].push_back(v);
        in_degree[v]++; // 将每个点的入度加一
    }
    vector<int> res = topo_sort(n);
    if (res.size() == n) { // 如果排序后节点数和原始节点数相等,说明拓扑排序成功
        for (auto u : res) {
            cout << u << ' ';
        }
    } else {
        cout << "There is a cycle in the graph." << endl; // 存在环,拓扑排序失败
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值