(持续更新)一些简单模板

1 图

1.1 并查集

class UF
{
    private:
        vector<int> father;
    public:
        UF(int n)
        {
            for(int i = 0; i <= n; i++)
                father.push_back(i);
        }
        int Find(int x)
        {
            if(father[x] != x)
            	father[x] = Find(father[x]);
            return father[x];
        }
        bool Union(int x, int y)
        {
            int fx = Find(x);
            int fy = Find(y);
            if(fx == fy)   return false;
            else
            {
                father[fx] = fy;
                return true;
            }
        }
};

1.2 kruskal

//最基本的kruskal求最小生成树
#include<bits/stdc++.h>
using namespace std;
struct edge
{
    int u, v;
    int cost;
    edge(int a, int b, int c): u(a), v(b), cost(c){}
    edge(){}
    bool operator<(const edge& e)const
    {
        return cost < e.cost;
    }
};
class UF
{
    private:
        vector<int> father;
    public:
        UF(int n)
        {
            for(int i = 0; i <= n; i++)
                father.push_back(i);
        }
        int Find(int x)
        {
            while(1)
            {
                if(father[x] == x)
                    return x;
                else
                    x = father[x];
            }
            return -1;
        }
        bool Union(int x, int y)
        {
            int fx = Find(x);
            int fy = Find(y);
            if(fx == fy)   return false;
            else
            {
                father[fx] = fy;
                return true;
            }
        }
};
int main()
{
    int n, a, b, c;
    while(cin >> n)
    {
        UF uf(n);
        vector<edge> v;
        for(int i = 0; i < n * (n - 1) / 2; i++)
        {
            cin >> a >> b >> c;
            v.push_back({a, b, c});
        }
        sort(v.begin(), v.end());
        int i = 0, ans = 0;
        while(i < n)
        {
            a = v[i].u;b = v[i].v;c = v[i].cost;
            if(uf.Find(a) != uf.Find(b))
            {
                uf.Union(a, b);
                ans += c;
            }
            i++;
        }
        cout << ans << endl;
    }
    return 0;
}

1.3 Prim

//就是有个Vmst节点集合,初始先选一个进去,然后从Vmst集合中所有点的临边中选一个最小边(一头在Vmst中,一头不在)的点加入,直到所有点加入
#include<bits/stdc++.h>
using namespace std;
int Prim(int cur, vector<vector<int>>& graph)
{
    int n = graph[0].size() - 1;
    int ans = 0, i = 1;
    vector<int> Vmst(n + 1, 0);
    Vmst[cur] = 1;
    while(i < n)
    {
        int mi = INT_MAX;
        int pos = 0;
        for(int k = 1; k <= n; k++)
        {
            if(Vmst[k])
                cur = k;
            else continue;
            for(int j = 1; j <= n; j++)
            {
                if(Vmst[j] != 1 && graph[cur][j] < mi)
                {
                    mi = graph[cur][j];
                    pos = j;
                }
            }
        }
        ans += mi;
        Vmst[pos] = 1;
        graph[cur][pos] = graph[pos][cur] = INT_MAX;
        i++;
    }
    return ans;
}
int main()
{
    int n, u, v, c;
    while(cin >> n)
    {
        vector<vector<int>> graph(n + 1, vector<int>(n + 1, 0));
        for(int i = 1; i <= n * (n - 1) / 2; i++)
        {
            cin >> u >> v >> c;
            graph[u][v] = c;
            graph[v][u] = c;
        }
        cout << Prim(1, graph) << endl;
    }
    return 0;
}

其中选最小边可以用最小堆优化

1.4 Dijkstra

//求单源非负权值的最短路径
#include<bits/stdc++.h>
using namespace std;
int main()
{
    int n, m, u, v, c;
    while(cin >> n >> m)
    {
        vector<vector<int>> g(n + 1, vector<int>(n + 1, INT_MAX));
        while(m--)
        {
            cin >> u >> v >> c;
            g[u][v] = c;
            g[v][u] = c;
        }
        for(int i = 1; i <= n; i++)
            g[i][i] = 0;
        vector<int> visited(n + 1, 0);
        vector<int> dist(n + 1, 0);
        int cnt = 1, u = 1, v;
        visited[u] = 1;
        for(int i = 1; i <= n; i++)
            dist[i] = g[u][i];
        while(cnt < n)
        {
            int mi = INT_MAX;
            //选出当前最小边加入到V中,可以用最小堆优化
            for(int i = 1; i <= n; i++)
            {
                if(visited[i] != 1 && dist[i] != INT_MAX && dist[i] < mi)
                {
                    mi = dist[i];
                    v = i;
                }
            }
            visited[v] = 1;
            //得到最小边v后,用v更新dist数组:松弛
            for(int i = 1; i <= n; i++)
                if(visited[i] != 1 && g[v][i] != INT_MAX && dist[v] + g[v][i] < dist[i])
                    dist[i] = dist[v] + g[v][i];
            cnt++;
        }
        cout << dist[n] << endl;
    }
    return 0;
}

1.5 Floyd

//求所有点的最短路径(稠密图较好)负权值也可
#include<bits/stdc++.h>
using namespace std;
int main()
{
    int n, m, u, v, c;
    while(cin >> n >> m)
    {
        vector<vector<int>> g(n + 1, vector<int>(n + 1, INT_MAX));
        while(m--)
        {
            cin >> u >> v >> c;
            g[u][v] = c;
            g[v][u] = c;
        }
        //重点!  !  ! 
        for(int k = 1; k <= n; k++)
        {
            for(int i = 1; i <= n; i++)
            {
                for(int j = 1; j <= n; j++)
                {
                    if(g[i][k] == INT_MAX || g[k][j] == INT_MAX)
                        continue;
                    if(g[i][j] == INT_MAX || g[i][k] + g[k][j] < g[i][j])
                        g[i][j] = g[i][k] + g[k][j];
                }
            }
        }
        cout << g[1][n] << endl;//1是起点,n是终点
    }
    return 0;
}

1.6 拓扑排序

判断DAG是否存在环

//通过拓扑排序判断DAG是否存在环:不断删除图中入度为0的点和所带的边,若点还没删完就找不到入度为0的点就说明有环
#include<bits/stdc++.h>
using namespace std;

int main()
{
    int n, m, u, v;
    while(cin >> n >> m)
    {
        vector<int> graph[n];
        vector<int> indegree(n, 0);
        while(m--)
        {
            cin >> u >> v;
            indegree[v]++;
        }
        int i = 0;
        queue<int> q;
        int f = 0;
        while(i < n)
        {
            for(int j = 0; j < n; j++)
            {
                if(indegree[j] == 0)
                    q.push(j);
            }
            if(q.empty())
            {
                f = 1;
                break;
            }
            else
            {
                int cur = q.front();
                q.pop();
                for(int k : graph[cur])
                {
                    indegree[k]--;
                }
            }
            i++;
        }
        if(f == 1)
            cout << "有环\n";
        else
            cout << "无环\n";
    }
    return 0;
}

2 搜索

这里的BFS是回溯,我没有看王道书,这是leetcode上的,可以参考这里

2.1 DFS

#include<bits/stdc++.h>
using namespace std;

class Solution {
public:
    void dfs(vector<vector<char>>& grid, int i, int j)
    {
        if(i < 0 || i >= grid.size() || j < 0 || j >= grid[0].size() || grid[i][j] != '1')
            return;
        grid[i][j] = '2';
        dfs(grid, i, j + 1);
        dfs(grid, i, j - 1);
        dfs(grid, i - 1, j);
        dfs(grid, i + 1, j);
    }
    int numIslands(vector<vector<char>>& grid) {
        int ans = 0;
        for(int i = 0; i < grid.size(); i++)
        {
            for(int j = 0; j < grid[0].size(); j++)
            {
                if(grid[i][j] == '1')
                {
                    dfs(grid, i, j);
                    ans++;
                }
            }
        }
        return ans;
    }
};

还有回溯法我的启蒙题目1774

class Solution {
public:
    void dfs(int level, int tmp, const vector<int> &a, int &ans , int target)
    {
        if(level == a.size())
        {
            if(abs(tmp - target) < abs(ans - target) || (abs(tmp - target) == abs(ans - target) && tmp < ans))
                ans = tmp;
            return ;
        }
        for(int i = 0; i < 3; i++)
        {
            dfs(level + 1, tmp + i * a[level], a, ans, target);
        }
    }
    int closestCost(vector<int>& baseCosts, vector<int>& toppingCosts, int target) 
    {
        int ans = INT_MAX;
        for(int i = 0; i < baseCosts.size(); i++)
        {
            dfs(0, baseCosts[i], toppingCosts, ans, target);
        }
        return ans;
    }


};

3 其他

3.1 不带括号的简单计算器

//表达式求值
#include<bits/stdc++.h>
using namespace std;
int priority(char c)
{
    if(c == '#')
            return 0;
    else if(c == '$')
            return 1;
    else if(c == '+' || c == '-')
        return 2;
    else if(c == '*' || c == '/')
            return 3;
}

int getNum(string s, int& i)
{
    int ans = 0;
    while(i < s.size() && isdigit(s[i]))
    {

        ans = ans * 10 + (s[i] - '0');
        i++;
    }
    return ans;
}
int main()
{
    int n;
    cin >> n;
    cin.get();
    while(n--)
    {
        string exp;
        stack<char>  op;
        op.push('#');
        stack<double> num;
        getline(cin, exp);
        exp += '$';
        int i = 0;
        while(i < exp.size())
        {
            if(exp[i] == ' ')
                i++; 
            else if(isdigit(exp[i]))
                num.push(getNum(exp, i));
            else
            {
                if(priority(exp[i]) > priority(op.top()))
                {
                    op.push(exp[i]);
                    i++;
                }
                else
                {
                    char order = op.top();
                    op.pop();
                    double x = num.top();
                    num.pop();
                    double y = num.top();
                    num.pop();
                    if(order == '+') num.push(x + y);
                    else if(order == '-') num.push(y - x);
                    else if(order == '*') num.push(x * y);
                    else if(order == '/') num.push(y / x);
                }
            }
            
        }
        cout << num.top() << endl;
    }
    return 0;
}

4 前缀

4.1 前缀树

class Trie {
private:
    bool isend;
    Trie * next[26];
public:
    /** Initialize your data structure here. */
    Trie() {
        isend = false;
        memset(next, 0, sizeof(next));
    }
    
    /** Inserts a word into the trie. */
    void insert(string word) {
        Trie* node = this;
        for(char ch: word)
        {
            if(node->next[ch - 'a'] == NULL)
                node->next[ch - 'a'] = new Trie();
            node = node->next[ch - 'a'];
        }
        node->isend = true;
    }
    
    /** Returns if the word is in the trie. */
    bool search(string word) {
        Trie* node = this;
        for(char ch : word)
        {
            if(node->next[ch - 'a'] != NULL)
                node = node->next[ch - 'a'];
            else return false;
        }
        return node->isend;
    }
    
    /** Returns if there is any word in the trie that starts with the given prefix. */
    bool startsWith(string prefix) {
        Trie* node = this;
        for(char ch : prefix)
        {
            if(node->next[ch - 'a'] != NULL)
                node = node->next[ch - 'a'];
            else return false;
        }
        return true;
    }
};

/**
 * Your Trie object will be instantiated and called as such:
 * Trie* obj = new Trie();
 * obj->insert(word);
 * bool param_2 = obj->search(word);
 * bool param_3 = obj->startsWith(prefix);
 */

4.2 前缀和

//求一维前缀和
#include<bits/stdc++.h>
using namespace std;
const int N = 100010;
int s[N];//全局变量初始化为0
int main()
{
    int n, m, l, r, tmp;
    scanf("%d %d", &n, &m);
    for(int i = 1; i <= n; i++)
    {
        scanf("%d", &tmp);
        s[i] = s[i - 1] + tmp;//数从1开始
    }
    while(m--)
    {
        scanf("%d %d", &l, &r);
        printf("%d\n", s[r] - s[l - 1]); 
    }
    return 0;
}

//求二维前缀和
#include<bits/stdc++.h>
using namespace std;
const int N = 1010;
int s[N][N];
int get_sum(int x1, int y1, int x2, int y2)
{
    return s[x2][y2] - s[x1 - 1][y2] - s[x2][y1 - 1] + s[x1 - 1][y1 - 1];
}
int main()
{
    int n, m, q, tmp, x1, x2, y1, y2;
    scanf("%d %d %d", &n, &m, &q);
    for(int i = 1; i <= n; i++)
    {
        for(int j = 1; j <= m; j++)
        {
            scanf("%d", &tmp);
            s[i][j] = s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1] + tmp;
        }
    }
    while(q--)
    {
        scanf("%d %d %d %d", &x1, &y1, &x2, &y2);
        printf("%d\n", get_sum(x1, y1, x2, y2));
    }
    return 0;
}

4.3 差分

#include<bits/stdc++.h>
using namespace std;
const int N = 100010;
int a[N], b[N];
void insert(int l, int r, int c)
{
    b[l] += c;
    b[r + 1] -= c;
}
int main()
{
    int n, m, l, r, c;
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; i++)
    {
        scanf("%d", &a[i]);
        insert(i, i, a[i]);
    }
    while(m--)
    {
        scanf("%d%d%d", &l, &r, &c);
        insert(l, r, c);
    }

    for(int i = 1; i <= n; i++)
    {
        a[i] = b[i] + a[i - 1];
        cout << a[i] << " ";
    }
    return 0;
}
#include<bits/stdc++.h>
using namespace std;
const int N =  1010;
int a[N][N], b[N][N];
void insert(int x1, int y1, int x2, int y2, int c)
{
    b[x1][y1] += c;
    b[x2 + 1][y1] -= c;
    b[x1][y2 + 1] -= c;
    b[x2 + 1][y2 + 1] += c;
}
int main()
{
    int n, m, x1, x2, y1, y2, c, q;
    scanf("%d%d%d", &n, &m, &q);
    for(int i = 1; i <= n; i++)
    {
        for(int j = 1; j <= m; j++)
        {
            scanf("%d", &a[i][j]);
            insert(i, j, i, j, a[i][j]);
        }
    }
    while(q--)
    {
        scanf("%d%d%d%d%d", &x1, &y1, &x2, &y2, &c);
        insert(x1, y1, x2, y2, c);
    }
    for(int i = 1; i <= n; i++)
    {
        for(int j = 1; j <= m; j++)
        {
            a[i][j] = a[i - 1][j] + a[i][j - 1] - a[i - 1][j - 1] + b[i][j];
            cout << a[i][j] << " "; 
        }
        cout << endl;
    }
    return 0;
}

5 字符串匹配KMP

#include<bits/stdc++.h>
using namespace std;

const int MAXM = 10000;
const int MAXN = 1000000; 
int nextT[MAXM];
char patten[MAXM];
char text[MAXN];
void getNext(int m)
{
    nextT[0] = 0;
    int q = 1, k = 0;
    for(; q < m; q++)
    {
        while(k > 0 && patten[q] != patten[k])
            k = nextT[k - 1];
        if(patten[q] == patten[k])
            k++;
        nextT[q] = k;
    }
}
int kmp(int n, int m)
{
    getNext(m);
    int k = 0;
    for(int i = 0; i < n; i++)
    {
        while(k > 0 && patten[k] != text[i])
            k = nextT[k - 1];
        if(patten[k] == text[i])
            k++;
        if(k == m)
            return i - m + 1;
    }
    return -1;
}
int main()
{
    int t;
    cin >> t;
    while(t--)
    {
        int n, m;
        cin >> n >> m;
        for(int i = 0; i < n; i++)
            cin >> text[i];
        for(int j = 0; j < m; j++)
            cin >> patten[j];
        cout << kmp(n, m) << endl;
    }
    return 0;
}

6 高精度

6.1 加

//高精度加法
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
vector<int> add(vector<int>& A, vector<int>& B)
{
    vector<int> C;
    int t = 0;
    for(int i = 0; i < A.size() || i < B.size(); i++)//这个也不错,就不用在外面分类了,代码更简洁一些
    {
        if(i < A.size())
            t += A[i];
        if(i < B.size())
            t += B[i];
        C.push_back(t % 10);
        t /= 10;
    }
    if(t)
        C.push_back(t);
    return C;
}
int main()
{
    vector<int> A, B;
    string a, b;
    cin >> a >> b;
    for(int i = a.size() - 1; i >= 0; i--)
        A.push_back(a[i] - '0');
    for(int i = b.size() - 1; i >= 0; i--)
        B.push_back(b[i] - '0');
    
    vector<int> C = add(A, B);

    for(int i = C.size() - 1; i >= 0; i--)
        cout << C[i];
    return 0;
}

6.2 减

//高精度减法
#include<bits/stdc++.h>
using namespace std;
bool cmp(vector<int>& A, vector<int>& B)
{
    if(A.size() != B.size())
        return A.size() > B.size();
    for(int i = A.size() - 1; i >= 0; i--)
        if(A[i] != B[i])
            return A[i] > B[i];
    return true;
}
vector<int> sub(vector<int>& A, vector<int>& B)
{
    vector<int> C;
    int t = 0;
    for(int i = 0; i < A.size(); i++)
    {
        t = A[i] - t;
        if(i < B.size()) t -= B[i];
        C.push_back((t + 10) % 10);
        if(t < 0) t = 1;
        else t = 0;
    }
    while(C.size() > 1 && C.back() == 0) C.pop_back();
    return C;
}
int main()
{
    vector<int> A, B;
    string a, b;
    cin >> a >> b;
    for(int i = a.size() - 1; i >= 0; i--)
        A.push_back(a[i] - '0');
    for(int i = b.size() - 1; i >= 0; i--)
        B.push_back(b[i] - '0');
    vector<int> C;
    if(cmp(A, B))
        C = sub(A, B);
    else
    {   cout << "-";
        C = sub(B, A);
    }
    for(int i = C.size() - 1; i >= 0; i--)
        cout << C[i];
    return 0;
}

6.3 乘

//高精度*高精度
#include<bits/stdc++.h>
using namespace std;
vector<int> mul(vector<int>& A, vector<int>& B)
{
    vector<int> C(A.size() + B.size());
    for(int i = 0; i < A.size(); i++)
        for(int j = 0; j < B.size(); j++)
            C[i + j] += A[i] * B[j];
    int t = 0;
    for(int i = 0; i < C.size() || t; i++)
    {
        if(i < C.size()) t += C[i];
        C[i] = t % 10;
        t = t / 10;
    }
    while(C.size() > 1 && C.back() == 0) C.pop_back();
    return C;
}
int main()
{
    string a, b;
    cin >> a >> b;
    vector<int> A, B, C;
    for(int i = a.size() - 1; i >= 0; i--) A.push_back(a[i] - '0');
    for(int j = b.size() - 1; j >= 0; j--) B.push_back(b[j] - '0');

    C = mul(A, B);
    for(int i = C.size() - 1; i >= 0; i--) cout << C[i];
    return 0;
}

7. 单调栈

//哨兵
//stk保存下标还是元素
for(int i = 0; i < n; i++)
{
    //递增栈为例:违反栈单调性的(计算/出栈)
	while(stk.size() && nums[i] < stk.top())
    {
        stk.pop();
        //calu
    }
    //按照单调性的加入栈中
    stk.push(nums[i]);
}

8. 滑动窗口

void maxofSileWindows(int n, int k)
{
	deque<int> dq;
    for(int i = 0; i < n; i++)
    {
        //只把最大值保存在dq中,前面小的都没用了
        while(dq.size() && nums[i] > nums[dq.back()])
            dq.pop_back();
        dq.push_back(i);
        //将不在窗口范围内的pop掉
        while(dq.size() && dq.front() < i - k + 1)
            dq.pop_front();
        //获得窗口内最大的元素
        if(dq.size() && i >= k - 1) 
            ans[idx++] = nums[dq.front()];
    }
}

9. 数学模板

9.1 快速幂

int qkm(int a, int k, int p) //计算a ^ k % p
{
    long long ans = 1;
    while(k)
    {
        if(k & 1)
            ans = ans * a % p;
        k = k >> 1;
        a = (long long) a * a % p;
    }
    return ans;
}
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值