好用算法 Trick
很大的数
表示一个很大的数,看类型包含多少字节写多少个 3f。
info
const int N = 0x3f3f3f3f;
判断是否为奇数
利用位运算判断奇数,因为奇数的二进制首位都是 1,和 1 相与后必定是 1,否则是 0。
- 结果为 true:是奇数
 - 结果为 false:是偶数
 
bool isEven(int num) {
    return num & 1;
}
建图
邻接表
法一:
const int N = 1e5 + 10, M = 2e5 + 10;
int h[N], e[M], ne[M], idx;
void add (int a, int b) {
    e[idx] = b;
    ne[idx] = h[a];
    h[a] = idx ++;
}   
法二:
typedef pair<int, int> PII; // first 为权,second 为连接的节点编号
vector<PII> h[N];
while (m --) {
    int a, b, c;
    cin >> a >> b >> c;
    h[a].push_back({c, b});
    h[b].push_back({c, a});
}
邻接矩阵
int g[N][N];
for (int i = 0; i < m; i++) {
    g[a][b] = g[b][a] = min(g[a][b], c); // 无向图
    g[a][b] = min(g[a][b], c); // 有向图
}
DFS(深度优先遍历)
tip
遍历不需要恢复现场,因为遍历完就结束了,不需要进行下一步操作
void dfs(int u, ...) { // ... 处可以加入下一层更新的参数
    st[u] = true;
    // ... 可填代码(往下层遍历之前的操作,可计数blahblah等操作)
    for (int i = 0;i < v[u].size(); i++) {
        int j = v[u][i]; //邻接表存,其值表示节点编号
        if (!st[u]) {
            // ... 前序
            dfs(j, ....);
            // ... 后序
        }
    }
    // ... 如果有返回值可以在这里返回
}
DFS(深度优先搜索)
tip
搜索需要恢复现场,因为搜索完之后后续可能需要用到这些元素,所以要恢复
void dfs(int u, ...) {
    if (u == n) return ; // 结束条件不唯一
    
    // ... 可做遍历前预处理,例如剪枝等
    
    for (int i = 0; i < n; i ++) {
        int j = g[u][i]; // 邻接矩阵存,值代表边权,i为节点编号
        if (!st[i] && ...) { // ... 处代表满足什么条件才往下搜
            // 记录现场,表示访问过,下次不在访问
            st[u] = true;
            dfs(i, ...);
            // 上一次的遍历结束了,开始遍历下一种情况,恢复现场
            st[u] = false;
        }
    }
}
BFS(广度优先遍历 / 广度优先搜索)
tip
BFS 需要用到队列,因为队列的特点就是有先后顺序(先进先出)的,而 BFS 遍历的过程中也是有先后顺序的,恰巧能够满足这一个特点。
在同一层中一般先遍历左边的节点,同时把要遍历的下一层节点加入到队列当中,然后再遍历右边的,然后再把下一层需要遍历的节点加入到队列中,很自然形成了一个先后顺序关系。
int bfs()
{
    queue<int> q;
    q.push(1); // 初始化队列,从根节点开始层序遍历...
    while (!q.empty())
    {
        int t = q.front();
        q.pop();  // 拿到之后将遍历之后的出队
        
        // 对节点 t 进行相应的操作,如打印等 ...
        
        // ... 将下一层要遍历的节点加入到队列当中
        if (...) q.push(...)
        if (...) q.push(...)
    }
    // ... 如果有返回值可以在这里返回
}
判断素数
bool isPrime(int x) {
    if (x == 2 || x == 3) 
        return true;
 
    if (x % 6 != 1 && x % 6 != 5)
        return false;
    for (int i = 5; i <= sqrt(x); i += 6) {
        if (x % i == 0 || x % (i + 2) == 0)
            return false;
    }
    return true;
}
STL
vector
vector<int> a(10); 
vector<int> a(10,0); 
vector<vector<int>> dp( 3 ,vector<int> (5,0));      //定义一个3X5的二维数组
vector<int> b(a); //用b向量来创建a向量,整体复制性赋值
vector<int> a(b.begin(),b.begin()+3); //定义了a值为b中第0个到第2个(共3个)元素
int b[7]={1,2,3,4,5,9,8};
vector<int> a(b,b+7); //从数组中获得初值
map
// map 转 vector
unordered_map<string, int> m;
vector<pair<string, int>> a(m.begin(), m.end());
string
//寻找子串: 在str寻找是否有curStr,返回下标
str.find(curStr) == string::npos
    
//截取子字符串: 从str中截取从下标0开始,length长度的字符串
resStr = str.substr(0,length);