图算法和数论算法基础模板汇总

深度优先搜索(DFS)

原理

DFS 是一种图遍历算法,通过沿着某一路径尽可能深地搜索,然后回溯到上一个节点继续搜索未访问的路径,直到所有节点都被访问。

应用场景

  • 检测连通性
  • 找出所有路径
  • 拓扑排序

时间复杂度

  • 时间复杂度:O(2^(V + E))
  • 空间复杂度:O(V)

模板代码

C++
#include <iostream>
#include <vector>
using namespace std;

void dfs(int u, vector<vector<int>>& g, vector<bool>& v) {
    v[u] = true;
    for (int n : g[u]) if (!v[n]) dfs(n, g, v);
}

int main() {
    vector<vector<int>> g = {{}, {2, 3}, {1, 4}, {1}, {2}};
    vector<bool> v(5, false);
    dfs(1, g, v);
    return 0;
}
Java
import java.util.*;

public class Main {
    public static void dfs(int u, List<List<Integer>> g, boolean[] v) {
        v[u] = true;
        for (int n : g.get(u)) if (!v[n]) dfs(n, g, v);
    }

    public static void main(String[] args) {
        List<List<Integer>> g = Arrays.asList(
            Arrays.asList(), Arrays.asList(2, 3), Arrays.asList(1, 4), Arrays.asList(1), Arrays.asList(2)
        );
        dfs(1, g, new boolean[5]);
    }
}
Python
def dfs(u, g, v):
    v[u] = True
    for n in g[u]:
        if not v[n]:
            dfs(n, g, v)

g = {1: [2, 3], 2: [1, 4], 3: [1], 4: [2], 5: []}
visited = [False] * 6
dfs(1, g, visited)

广度优先搜索(BFS)

原理

BFS 是一种层次遍历算法,从起始节点开始,依次访问距离为 1、2、3… 的所有节点,直至图中所有节点都被访问。

应用场景

  • 最短路径搜索(无权图)
  • 寻找连通分量
  • 分层遍历问题

时间复杂度

  • 时间复杂度:O(V + E)
  • 空间复杂度:O(V)

模板代码

C++
#include <iostream>
#include <vector>
#include <queue>
using namespace std;

void bfs(int s, vector<vector<int>>& g, vector<bool>& v) {
    queue<int> q; q.push(s); v[s] = true;
    while (!q.empty()) {
        int u = q.front(); q.pop();
        for (int n : g[u]) if (!v[n]) q.push(n), v[n] = true;
    }
}

int main() {
    vector<vector<int>> g = {{}, {2, 3}, {4}, {1}, {}, {}};
    vector<bool> v(6, false);
    bfs(1, g, v);
    return 0;
}
Java
import java.util.*;

public class Main {
    public static void bfs(int s, List<List<Integer>> g, boolean[] v) {
        Queue<Integer> q = new LinkedList<>();
        q.add(s); v[s] = true;
        while (!q.isEmpty()) {
            int u = q.poll();
            for (int n : g.get(u)) if (!v[n]) q.add(n), v[n] = true;
        }
    }

    public static void main(String[] args) {
        List<List<Integer>> g = Arrays.asList(
            Arrays.asList(), Arrays.asList(2, 3), Arrays.asList(4), Arrays.asList(1), Arrays.asList(), Arrays.asList()
        );
        bfs(1, g, new boolean[6]);
    }
}
Python
from collections import deque

def bfs(s, g, v):
    q = deque([s])
    v[s] = True
    while q:
        u = q.popleft()
        for n in g[u]:
            if not v[n]:
                q.append(n)
                v[n] = True

g = {1: [2, 3], 2: [4], 3: [1], 4: [], 5: []}
visited = [False] * 6
bfs(1, g, visited)

Dijkstra 算法

原理

Dijkstra 是一种单源最短路径算法,适用于边权为非负的图。通过一个优先队列,每次扩展当前距离最短的节点,逐步计算到其他节点的最短距离。

应用场景

  • 图中带权最短路径问题

时间复杂度

  • 时间复杂度:O((V + E) * log V)
  • 空间复杂度:O(V)

模板代码

C++
#include <iostream>
#include <vector>
#include <queue>
#include <climits>
using namespace std;

typedef pair<int, int> P;

void dijkstra(int s, vector<vector<P>>& g, vector<int>& d) {
    priority_queue<P, vector<P>, greater<P>> pq;
    d[s] = 0; pq.push({0, s});
    while (!pq.empty()) {
        int u = pq.top().second; pq.pop();
        for (auto e : g[u]) if (d[u] + e.first < d[e.second]) {
            d[e.second] = d[u] + e.first;
            pq.push({d[e.second], e.second});
        }
    }
}

int main() {
    vector<vector<P>> g(6);
    g[1].push_back({2, 2}); g[1].push_back({4, 3}); g[2].push_back({1, 4});
    vector<int> d(6, INT_MAX);
    dijkstra(1, g, d);
    return 0;
}
Java
import java.util.*;

public class Main {
    public static void dijkstra(int s, List<List<int[]>> g, int[] d) {
        PriorityQueue<int[]> pq = new PriorityQueue<>(Comparator.comparingInt(a -> a[0]));
        d[s] = 0; pq.add(new int[]{0, s});
        while (!pq.isEmpty()) {
            int u = pq.poll()[1];
            for (int[] e : g.get(u)) if (d[u] + e[0] < d[e[1]]) {
                d[e[1]] = d[u] + e[0];
                pq.add(new int[]{d[e[1]], e[1]});
            }
        }
    }

    public static void main(String[] args) {
        List<List<int[]>> g = Arrays.asList(
            Arrays.asList(), Arrays.asList(new int[]{2, 2}, new int[]{4, 3}), Arrays.asList(new int[]{1, 4}), Arrays.asList(), Arrays.asList(), Arrays.asList()
        );
        int[] d = new int[6];
        Arrays.fill(d, Integer.MAX_VALUE);
        dijkstra(1, g, d);
    }
}
Python
import heapq

def dijkstra(s, g, d):
    d[s] = 0
    pq = [(0, s)]
    while pq:
        u = heapq.heappop(pq)[1]
        for w, n in g[u]:
            if d[u] + w < d[n]:
                d[n] = d[u] + w
                heapq.heappush(pq, (d[n], n))

g = {1: [(2, 2), (4, 3)], 2: [(1, 4)], 3: [], 4: [], 5: []}
dist = [float('inf')] * 6
dijkstra(1, g, dist)

质数判断

质数是大于 1 且仅能被 1 和自身整除的数。判断质数是许多算法和数学问题的基础。

原理:

  • 枚举从 2 到 n \sqrt{n} n 的所有整数,判断是否能整除 n n n。若发现任何一个整数 d d d,使得 n % d = = 0 n \% d == 0 n%d==0,则 n n n 不是质数。
  • 优化点:跳过偶数,只检查 2 和奇数。

应用场景:

  • 质因数分解。

时间复杂度:

  • O ( n ) O(\sqrt{n}) O(n )

代码模板:

C++:

bool isPrime(int n) {
    if (n <= 1) return false;
    if (n <= 3) return true;
    if (n % 2 == 0 || n % 3 == 0) return false;
    for (int i = 5; i * i <= n; i ++ ) {
        if (n % i == 0) return false;
    }
    return true;
}

Java:

public boolean isPrime(int n) {
    if (n <= 1) return false;
    if (n <= 3) return true;
    if (n % 2 == 0 || n % 3 == 0) return false;
    for (int i = 5; i * i <= n; i ++ ) {
        if (n % i == 0) return false;
    }
    return true;
}

Python:

def is_prime(n):
    if n <= 1:
        return False
    if n <= 3:
        return True
    if n % 2 == 0 or n % 3 == 0:
        return False
    i = 5
    while i * i <= n:
        if n % i == 0:
            return False
        i += 6
    return True

最大公约数(GCD)

最大公约数是两个整数的所有公约数中最大的一个。

原理:

  • 欧几里得算法:利用性质 g c d ( a , b ) = g c d ( b , a % b ) gcd(a, b) = gcd(b, a \% b) gcd(a,b)=gcd(b,a%b) 递归或迭代求解。

应用场景:

  • 化简分数。

时间复杂度:

  • O ( log ⁡ min ⁡ ( a , b ) ) O(\log\min(a, b)) O(logmin(a,b))

代码模板:

C++:

int gcd(int a, int b) {
    while (b != 0) {
        int temp = a % b;
        a = b;
        b = temp;
    }
    return a;
}

Java:

public int gcd(int a, int b) {
    while (b != 0) {
        int temp = a % b;
        a = b;
        b = temp;
    }
    return a;
}

Python:

def gcd(a, b):
    while b != 0:
        a, b = b, a % b
    return a

组合数

组合数 C ( n , k ) C(n, k) C(n,k) 表示从 n n n 个元素中选取 k k k 个的不同组合数。

公式:

C ( n , k ) = n ! k ! ( n − k ) ! C(n, k) = \frac{n!}{k!(n-k)!} C(n,k)=k!(nk)!n!

优化:

  • 使用递推关系 C ( n , k ) = C ( n − 1 , k ) + C ( n − 1 , k − 1 ) C(n, k) = C(n-1, k) + C(n-1, k-1) C(n,k)=C(n1,k)+C(n1,k1)
  • 直接计算公式,避免使用全量阶乘。

应用场景:

  • 概率统计。
  • 计数问题。

时间复杂度:

  • 递推: O ( n × k ) O(n \times k) O(n×k)
  • 直接计算: O ( k ) O(k) O(k)

代码模板:

C++:

long long combination(int n, int k) {
    if (k > n) return 0;
    if (k == 0 || k == n) return 1;
    long long res = 1;
    for (int i = 1; i <= k; ++i) {
        res = res * (n - i + 1) / i;
    }
    return res;
}

Java:

public long combination(int n, int k) {
    if (k > n) return 0;
    if (k == 0 || k == n) return 1;
    long res = 1;
    for (int i = 1; i <= k; ++i) {
        res = res * (n - i + 1) / i;
    }
    return res;
}

Python:

def combination(n, k):
    if k > n:
        return 0
    if k == 0 or k == n:
        return 1
    res = 1
    for i in range(1, k + 1):
        res = res * (n - i + 1) // i
    return res

线性筛法(埃氏筛优化)

线性筛是一种高效生成质数表的方法,避免了冗余标记。

原理:

  • 每个合数只被其最小质因数标记一次。

应用场景:

  • 质数表生成。

时间复杂度:

  • O ( n ) O(n) O(n)

代码模板:

C++:

vector<int> linearSieve(int n) {
    vector<int> primes;
    vector<bool> isPrime(n + 1, true);
    for (int i = 2; i <= n; ++i) {
        if (isPrime[i]) primes.push_back(i);
        for (int p : primes) {
            if (i * p > n) break;
            isPrime[i * p] = false;
            if (i % p == 0) break;
        }
    }
    return primes;
}

Java:

public List<Integer> linearSieve(int n) {
    List<Integer> primes = new ArrayList<>();
    boolean[] isPrime = new boolean[n + 1];
    Arrays.fill(isPrime, true);
    for (int i = 2; i <= n; ++i) {
        if (isPrime[i]) primes.add(i);
        for (int p : primes) {
            if (i * p > n) break;
            isPrime[i * p] = false;
            if (i % p == 0) break;
        }
    }
    return primes;
}

Python:

def linear_sieve(n):
    primes = []
    is_prime = [True] * (n + 1)
    for i in range(2, n + 1):
        if is_prime[i]:
            primes.append(i)
        for p in primes:
            if i * p > n:
                break
            is_prime[i * p] = False
            if i % p == 0:
                break
    return primes

快速幂

快速幂是一种高效计算 a b % p a^b \% p ab%p 的方法。

原理:

  • b b b 按二进制拆分,利用 a b = ( a b / 2 ) 2 a^{b} = (a^{b/2})^2 ab=(ab/2)2

应用场景:

  • 模运算。
  • 大整数幂计算。

时间复杂度:

  • O ( log ⁡ b ) O(\log b) O(logb)

代码模板:

C++:

long long fastPower(long long a, long long b, long long p) {
    long long res = 1;
    a %= p;
    while (b > 0) {
        if (b & 1) res = res * a % p;
        a = a * a % p;
        b >>= 1;
    }
    return res;
}

Java:

public long fastPower(long a, long b, long p) {
    long res = 1;
    a %= p;
    while (b > 0) {
        if ((b & 1) == 1) res = res * a % p;
        a = a * a % p;
        b >>= 1;
    }
    return res;
}

Python:

def fast_power(a, b, p):
    res = 1
    a %= p
    while b > 0:
        if b & 1:
            res = res * a % p
        a = a * a % p
        b >>= 1
    return res
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值