Cpp算法笔记


万能头文件

#include <bits/stdc++.h>

排序

外部函数

bool cmp(T a, T b){
    return //sort rule;
}

void main(){
    sort(nums.begin(), nums.end(), cmp);
}

Lambda表达式

sort(nums.begin(),nums.end(),[](T &a, T &b){
    return //sort rule;
});

快速排序模板

int Partition(int A[], int left, int right){
    int tmp = A[left];
    while(left<right){
        while(left<right&&A[right]>tmp) right--;
        A[left] = A[right];
        while(left<right&&A[left]<=tmp) left++;
        A[right] = A[left];
    }
    A[left] = tmp;
    return left;
}

void quickSort(int A[], int left, int right){
    if(left<right){
        int pos = Partition(A, left, right);
        quickSort(A, left, pos-1);
        quickSort(A, pos+1, right);
    }
}

//choose random principal point
int randPartition(int A[], int left, int right){
    int p = round(1.0*rand()/RAND_MAX*(right-left)+left);//生成[left,right]内的随机数;
    swap(A[p],A[left]);
    //same as Partition
    int tmp = A[left];
    while(left<right){
        while(left<right&&A[right]>tmp) right--;
        A[left] = A[right];
        while(left<right&&A[left]<=tmp) left++;
        A[right] = A[left];
    }
    A[left] = tmp;
    return left;

}

二分查找

查看元素是否存在

//template
int binarySearch(int A[], int left, int right, int target){
    while(left<=right){
        int mid = left + (right-left)/2;
        if(A[mid]==target) return mid;
        else if(A[mid]>x){
            right = mid - 1;
        }else{
            left = mid + 1;
        }
    }
    return -1;
}
//STL
binary_search(nums.begin(), nums.end(), target);

求序列中第一个大于等于target的元素的位置

//template
int lower_bound(int A[], int left, int right, int target){
    while(left<right){
        int mid = left + (right-left)/2;
        if(A[mid]>=x){
            right = mid;
        }else{
            left = mid + 1;
        }
    }
    return left;
}

//STL
lower_bound(nums.begin(), nums.end(), target, [](const T target, const T &a){
    return //rule;
});

求序列中第一个大于target的元素的位置

//template
int upper_bound(int A[], int left, int right, int target){
    while(left<right){
        int mid = left + (right-left)/2;
        if(A[mid]>x){
            right = mid;
        }else{
            left = mid + 1;
        }
    }
    return left;
}

//STL
upper_bound(nums.begin(), nums.end(), target, [](const T target, const T &a){
    return //rule;
});

数学

快速幂

求解a^b%m

递归写法

typedef long long LL;
LL binaryPow(LL a, LL b, LL m){
    if(b==0) return 1;
    if(b&1){
        return a*binaryPow(a, b-1, m)%m;//if b is an odd num, convert to b-1
    }else{
        LL mul = binaryPow(a, b/2, m);//if b is an even num, convert to b/2
        return mul*mul%m;
    }
}

迭代写法

typedef long long LL;
LL binaryPow(LL a, LL b, LL m){
    LL ans = 1;
    while(b>0){
        if(b&1){
            ans = ans*a%m;
        }
        a = a*a%m;
        b >>= 1;
    }
    return ans;
}

素数筛

#define maxn 1000000
bool vis[maxn];
int prime[maxn], primeNums;

埃氏筛

void aiShiShai(int n){
    for(int i = 2; i<=n; i++){
        if(!vis[i]) prime[primeNums++] = i;
        for(int j = 2; j*i<=n; j++){
            vis[i*j] = true;
        }
    }
}

欧拉筛

void ouLaShai(int n){
    for(int i = 2; i<=n; i++){
        if(!vis[i]) prime[primeNums++] = i;
        for(int j = 0; j<primeNums; j++){
            if(i*prime[j]>n) break;
            vis[i*prime[j]] = true;
            if(i%prime[j]==0) break;
        }
    }
}

STL

priority_queue

priority_queue<T, vector<T>, less<T>> q;//big num, high priority
priority_queue<T, vector<T>, greater<T>> q;//small num, low priority 

//priority setting of struct
//friend
struct fruit{
    string name;
    int price;
    friend bool operator < (fruit f1, fruit f2){
        return f1.price < f2.price;//价格高的优先级高
    }
}
priority_queue<fruit> q;

//cmp
struct cmp{
    bool operator()(fruit f1, fruit f2){
        return f1.price>f2.price;
    }
}//the operator is contrast to the sort
priority_queue<T, vector<T>, cmp> q;

//lambda
 auto cmp = [](const T& a, const T& b) -> bool {
             return a.second < b.second; 
        };
 priority_queue<T, vector<T>, decltype(cmp)> que(cmp);

并查集

class UnionFind {
private:
    vector<int> parent;
    int n_areas;
public:
    UnionFind(int n) {
        parent.resize(n);
        n_areas = n;
        for (int i = 0; i < n; i++) parent[i] = i;
    }

    //recursion
    int Find(int x) {
        if (parent[x] != x) {
            parent[x] = Find(parent[x]);
        }

        return parent[x];
    }

    //iteration
    int Find(int x){
        int tmp = x;
        while(x!=parent[x]){
            x = parent[x];
        }
        while(tmp!=parent[tmp]){
            int z = tmp;
            tmp = parent[tmp];
            parent[z] = x;
        }
        return x;
    }

    void Union(int x, int y) {
        int root_x = Find(x);
        int root_y = Find(y);
        if (root_x == root_y) return;

        parent[root_y] = root_x;
        n_areas--;
    }

    int get_total_areas() {
        return n_areas;
    }
};

图算法

Dijkstra算法

int n, G[MAXV][MAXV];//n is the num of nodes, MAXV is the max num of nodes
int dis[MAXV];
bool vis[MAXV] = {false};

void Dijkstra(int start){
    fill(d,d+MAXV,INF);
    dis[start] = 0;
    for(int i = 0; i<n; i++){
        int u = -1, MIN = INF;
        for(int j = 0; j<n; j++){
            if(vis[j]==false && d[j]<MIN){
                u = j;
                MIN = d[j];
            }
        }
        //can't find d[u] smaller than INF,means the rest nodes do not connect with start
        if(u==-1) return;
        vis[u] = true;
        for(int v = 0; v<n; v++){
            if(vis[v] == false && G[u][v]!=INF && d[u] + G[u][v] < d[v]){
                d[v] = d[u] + G[u][v];
            }
        }
    }
}

Floyd算法

const int MAXV = 200;
int n,m;//n is num of the nodes, m is the num of edges
int dis[MAXV][MAXV];//minimum dis between i, j

void Floyd(){
    for(int k = 0; k<n; k++){
        for(int i = 0; i<n; i++){
            for(int j = 0; j<n; j++){
                if(dis[i][k]!=INF && dis[k][j]!=INF && dis[i][k]+dis[k][j]<dis[i][j]){
                    dis[i][j] = dis[i][k] + dis[k][j];
                }
            }
        }
    }
}

Prim算法

int n, G[MAXV][MAXV];//n is the num of nodes, MAXV is the max num of nodes
int d[MAXV];
bool vis[MAXV] = {false};

int prim(){
    fill(d, d+MAXV,INT);
    d[0] = 0;
    int ans = 0;//sum of minimum spanning tree;
    for(int i = 0; i<n; i++){
        int u = -1, MIN = INF;
        for(int j = 0; j<n; j++){
            if(vis[j]==false && d[j]<MIN){
                u = j;
                MIN = d[j];
            }
        }
        //can't find d[u] smaller than INF,means the rest nodes do not connect with start
        if(u==-1) return -1;
        vis[u] = true;
        ans += d[u];
        for(int v = 0; v<n; v++){
            if(vis[v] == false && G[u][v]!=INF && d[u] + G[u][v] < d[v]){
                d[v] = G[u][v];
            }
        }
    }
    return ans;
}

Kruskal算法

struct edge{
    int u, v;
    int cost;
}E[MAXE];

int Kruskal(int n, int m){
    int ans = 0;
    UnionFind U(n);
    sort(E,E+m,[](struct edge a, struct edge b){
        return a.cost<b.cost;
    });
    for(int i = 0; i<m; i++){
        int faU = U.Find(E[i].u);
        int faV = U.Find(E[i].v);
        if(faU!=faV){
            U.Union(faU,faV);
            and += E[i].cost;
            if(U.get_total_areas()==1) break;
        }
    }
    if(U.get_total_areas()==1) return -1;
    else return ans;
}

拓扑排序

vector<int> G[MAXV];
int n, m inDegree[MAXV];

bool topologicalSort(){
    int num = 0;//num of nodes in the topological sequence
    queue<int> q;
    for(int i = 0; i<n; i++){
        if(inDegree[i]==0){
            q.push(i);
        }
    }
    while(!q.empty()){
        int u = q.front();
        q.pop();
        for(int i = 0; i<G[u].size(); i++){
            int v = G[u][i];
            inDegree[v]--;
            if(inDegree[v]==0){
                q.push(v);
            }
        }
        G[u].clear();
        num++;
    }
    if(num==n) return true;
    else return false;
}

动态规划

01背包问题

有n件物品,每件物品的重量为w[i],价值为c[i],现有一个容量为V的背包,问如何选取物品放入背包,使得背包内物品的价值最大,其中每种物品都只有一件  

dp[i][v]表示前i件物品恰好装入容量为v的背包中所能获得的最大价值

for(int i = 1; i<=n; i++){
    for(int v = w[i]; v<=V; v++){
        dp[i][v] = max(dp[i-1][v], dp[i-1][v-w[i]]+c[i]);
    }
}

滚动数组优化:

for(int i = 1; i<=n; i++){
    for(int v = V; v>=w[i]; v--){
        dp[v] = max(dp[v], dp[v-w[i]] + c[i]);
    }
}

完全背包

有n种物品,每种物品的单件重量为w[i],价值为c[i]。现有一个容量为V的背包,问如何选取物品放入背包,使得背包内物品的总价值最大,每种物品都有无穷件。

dp[i][v]表示前i件物品恰好装入容量为v的背包中所能获得的最大价值

for(int i = 1; i<=n; i++){
    for(int v = w[i]; v<=V; v++){
        dp[i][v] = max(dp[i-1][v], dp[i][v-w[i]]+c[i]);
    }
}

滚动数组优化

for(int i = 1; i<=n; i++){
    for(int v = w[i]; v<=V; v++){
        dp[v] = max(dp[v], dp[v-w[i]] + c[i]);
    }
}

字典树

Trie(发音类似 “try”)或者说 前缀树 是一种树形数据结构,用于高效地存储和检索字符串数据集中的键。这一数据结构有相当多的应用情景,例如自动补完和拼写检查。

class Trie {
    Trie *child[26];
    bool isWord;
public:
    /** Initialize your data structure here. */
    Trie() {
        isWord = false;
        for(int i=0;i<26;i++){
            child[i] = nullptr;
        }
    }
    
    /** Inserts a word into the trie. */
    void insert(string word) {
        Trie *t = this;
        for(char c: word){
            if(!t -> child[c-'a']){
                t->child[c-'a'] = new Trie();
            }
            t = t->child[c-'a'];
        }
        t->isWord = true;
    }
    
    /** Returns if the word is in the trie. */
    bool search(string word) {
        Trie *t = this;
        for(char c:word){
            if(!t -> child[c - 'a']){
                return false;
            }
            t = t->child[c - 'a'];
        }
        return t->isWord;
    }
    
    /** Returns if there is any word in the trie that starts with the given prefix. */
    bool startsWith(string prefix) {
        Trie *t = this;
        for(char c:prefix){
            if(!t->child[c-'a']){
                return false;
            }
            t = t->child[c - 'a'];
        }
        return true;
    }
};

其他

lowbit

能被x整除的最大2的幂次

lowbit(x) = x&(-x)

位运算

a^b^c == a^c^b
0 ^ n = n;
n ^ n = 0;

求1+2+…+n

int sumNums(int n) {
    n && (n += sumNums(n-1));
    return n;
}

不用加减乘除法做加法

//^表示无进位求和
//&表示求每位的进位数
 int add(int a, int b) {
    if(a == 0){
        return b;
    }
    if(b == 0){
        return a; 
    }
    return add(a^b, (unsigned)(a&b) << 1); 
}

Author: WTY
Reprint policy: All articles in this blog are used except for special statements CC BY 4.0 reprint polocy. If reproduced, please indicate source WTY !
  TOC