Essential Algorithm Templates in C++

Number Theory

Primality Testing via Trial Division

#include <iostream>
using namespace std;

bool isPrime(int num) {
    if (num < 2) return false;
    for (int d = 2; d <= num / d; ++d)
        if (num % d == 0) return false;
    return true;
}

int main() {
    int queries;
    cin >> queries;
    while (queries--) {
        int val;
        cin >> val;
        cout << (isPrime(val) ? "Yes" : "No") << endl;
    }
    return 0;
}

Prime Factorization

#include <iostream>
using namespace std;

void factorize(int n) {
    for (int d = 2; d <= n / d; ++d) {
        if (n % d == 0) {
            int exp = 0;
            while (n % d == 0) {
                ++exp;
                n /= d;
            }
            cout << d << ' ' << exp << endl;
        }
    }
    if (n > 1) cout << n << " 1" << endl;
}

int main() {
    int count;
    cin >> count;
    while (count--) {
        int val;
        cin >> val;
        factorize(val);
        cout << endl;
    }
    return 0;
}

Sieve of Eratosthenes

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

void sieve(int limit) {
    vector<bool> isPrime(limit + 1, true);
    vector<int> primes;
    for (int i = 2; i <= limit; ++i) {
        if (isPrime[i]) {
            primes.push_back(i);
            for (long long j = (long long)i * i; j <= limit; j += i)
                isPrime[j] = false;
        }
    }
    for (int p : primes) cout << p << ' ';
    cout << endl << primes.size();
}

int main() {
    int n;
    cin >> n;
    sieve(n);
    return 0;
}

Linear Sieve

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

void linearSieve(int limit) {
    vector<int> primes;
    vector<bool> composite(limit + 1, false);
    for (int i = 2; i <= limit; ++i) {
        if (!composite[i]) primes.push_back(i);
        for (int p : primes) {
            if (i * p > limit) break;
            composite[i * p] = true;
            if (i % p == 0) break;
        }
    }
    cout << primes.size();
}

int main() {
    int n;
    cin >> n;
    linearSieve(n);
    return 0;
}

Divisors via Trial Division

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

void listDivisors(int x) {
    vector<int> divisors;
    for (int d = 1; d <= x / d; ++d) {
        if (x % d == 0) {
            divisors.push_back(d);
            if (d != x / d) divisors.push_back(x / d);
        }
    }
    sort(divisors.begin(), divisors.end());
    for (int d : divisors) cout << d << ' ';
}

int main() {
    int t;
    cin >> t;
    while (t--) {
        int val;
        cin >> val;
        listDivisors(val);
        cout << endl;
    }
    return 0;
}

Count of Divisors

#include <iostream>
#include <unordered_map>
using namespace std;
const int MOD = 1e9 + 7;

int main() {
    int n;
    cin >> n;
    unordered_map<int, int> factorCount;
    while (n--) {
        int val;
        cin >> val;
        for (int d = 2; d <= val / d; ++d)
            while (val % d == 0) {
                ++factorCount[d];
                val /= d;
            }
        if (val > 1) ++factorCount[val];
    }
    long long result = 1;
    for (auto &[prime, cnt] : factorCount)
        result = result * (cnt + 1) % MOD;
    cout << result;
    return 0;
}

Sum of Divisors

#include <iostream>
#include <unordered_map>
using namespace std;
const int MOD = 1e9 + 7;

int main() {
    int n;
    cin >> n;
    unordered_map<int, int> factorCount;
    while (n--) {
        int val;
        cin >> val;
        for (int d = 2; d <= val / d; ++d)
            while (val % d == 0) {
                ++factorCount[d];
                val /= d;
            }
        if (val > 1) ++factorCount[val];
    }
    long long total = 1;
    for (auto &[prime, cnt] : factorCount) {
        long long term = 1, power = 1;
        for (int i = 0; i < cnt; ++i) {
            power = power * prime % MOD;
            term = (term + power) % MOD;
        }
        total = total * term % MOD;
    }
    cout << total;
    return 0;
}

Greatest Common Divisor

#include <iostream>
using namespace std;

int gcd(int a, int b) {
    return b == 0 ? a : gcd(b, a % b);
}

int main() {
    int t;
    cin >> t;
    while (t--) {
        int x, y;
        cin >> x >> y;
        cout << gcd(x, y) << endl;
    }
    return 0;
}

Least Common Multiple

#include <iostream>
using namespace std;

int gcd(int a, int b) {
    return b == 0 ? a : gcd(b, a % b);
}

int main() {
    int t;
    cin >> t;
    while (t--) {
        int x, y;
        cin >> x >> y;
        cout << x / gcd(x, y) * y << endl;
    }
    return 0;
}

Euler's Toteint Function

#include <iostream>
using namespace std;

int phi(int n) {
    int result = n;
    for (int d = 2; d <= n / d; ++d) {
        if (n % d == 0) {
            while (n % d == 0) n /= d;
            result -= result / d;
        }
    }
    if (n > 1) result -= result / n;
    return result;
}

int main() {
    int t;
    cin >> t;
    while (t--) {
        int val;
        cin >> val;
        cout << phi(val) << endl;
    }
    return 0;
}

Fast Exponentiation

#include <iostream>
using namespace std;

long long power(long long base, long long exp, long long mod) {
    long long result = 1 % mod;
    while (exp) {
        if (exp & 1) result = result * base % mod;
        base = base * base % mod;
        exp >>= 1;
    }
    return result;
}

int main() {
    int t;
    cin >> t;
    while (t--) {
        long long a, b, p;
        cin >> a >> b >> p;
        cout << power(a, b, p) << endl;
    }
    return 0;
}

Modular Inverse via Fermat's Theorem

#include <iostream>
using namespace std;

long long modPow(long long base, long long exp, long long mod) {
    long long result = 1 % mod;
    while (exp) {
        if (exp & 1) result = result * base % mod;
        base = base * base % mod;
        exp >>= 1;
    }
    return result;
}

int main() {
    int t;
    cin >> t;
    while (t--) {
        long long a, p;
        cin >> a >> p;
        if (a % p == 0) cout << "impossible" << endl;
        else cout << modPow(a, p - 2, p) << endl;
    }
    return 0;
}

Extended Euclidean Algorithm

#include <iostream>
using namespace std;

int extendedGcd(int a, int b, int &x, int &y) {
    if (b == 0) {
        x = 1, y = 0;
        return a;
    }
    int d = extendedGcd(b, a % b, y, x);
    y -= a / b * x;
    return d;
}

int main() {
    int t;
    cin >> t;
    while (t--) {
        int a, b, x, y;
        cin >> a >> b;
        extendedGcd(a, b, x, y);
        cout << x << ' ' << y << endl;
    }
    return 0;
}

Modular Inverse via Extneded Euclidean Algorithm

#include <iostream>
using namespace std;

int extendedGcd(int a, int b, int &x, int &y) {
    if (b == 0) {
        x = 1, y = 0;
        return a;
    }
    int d = extendedGcd(b, a % b, y, x);
    y -= a / b * x;
    return d;
}

int main() {
    int t;
    cin >> t;
    while (t--) {
        int a, p, x, y;
        cin >> a >> p;
        int d = extendedGcd(a, p, x, y);
        if (d != 1) cout << "impossible" << endl;
        else cout << ((long long)x % p + p) % p << endl;
    }
    return 0;
}

Binomial Coefficients (Small Range)

#include <iostream>
#include <vector>
using namespace std;
const int MOD = 1e9 + 7, MAX = 2000;

int main() {
    vector<vector<int>> comb(MAX + 1, vector<int>(MAX + 1, 0));
    for (int i = 0; i <= MAX; ++i) {
        comb[i][0] = comb[i][i] = 1;
        for (int j = 1; j < i; ++j)
            comb[i][j] = (comb[i-1][j] + comb[i-1][j-1]) % MOD;
    }
    int t;
    cin >> t;
    while (t--) {
        int n, k;
        cin >> n >> k;
        cout << comb[n][k] << endl;
    }
    return 0;
}

Binomial Coefficients (Large Range)

#include <iostream>
#include <vector>
using namespace std;
const int MOD = 1e9 + 7, MAX = 1e5;

long long modPow(long long base, long long exp) {
    long long result = 1 % MOD;
    while (exp) {
        if (exp & 1) result = result * base % MOD;
        base = base * base % MOD;
        exp >>= 1;
    }
    return result;
}

int main() {
    vector<long long> fact(MAX + 1, 1), invFact(MAX + 1, 1);
    for (int i = 1; i <= MAX; ++i) {
        fact[i] = fact[i-1] * i % MOD;
        invFact[i] = modPow(fact[i], MOD - 2);
    }
    int t;
    cin >> t;
    while (t--) {
        int n, k;
        cin >> n >> k;
        cout << fact[n] * invFact[k] % MOD * invFact[n-k] % MOD << endl;
    }
    return 0;
}

Graph Theory

Topological Sorting

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

int main() {
    int vertices, edges;
    cin >> vertices >> edges;
    vector<vector<int>> adj(vertices + 1);
    vector<int> indegree(vertices + 1, 0);
    while (edges--) {
        int u, v;
        cin >> u >> v;
        adj[u].push_back(v);
        ++indegree[v];
    }
    queue<int> q;
    for (int i = 1; i <= vertices; ++i)
        if (indegree[i] == 0) q.push(i);
    vector<int> order;
    while (!q.empty()) {
        int u = q.front(); q.pop();
        order.push_back(u);
        for (int v : adj[u])
            if (--indegree[v] == 0) q.push(v);
    }
    if (order.size() != vertices) cout << -1;
    else for (int u : order) cout << u << ' ';
    return 0;
}

Dijkstra's Algorithm (Naive)

#include <iostream>
#include <vector>
#include <climits>
using namespace std;

int main() {
    int vertices, edges;
    cin >> vertices >> edges;
    vector<vector<pair<int, int>>> graph(vertices + 1);
    while (edges--) {
        int u, v, w;
        cin >> u >> v >> w;
        graph[u].emplace_back(v, w);
    }
    vector<int> dist(vertices + 1, INT_MAX);
    vector<bool> visited(vertices + 1, false);
    dist[1] = 0;
    for (int i = 0; i < vertices; ++i) {
        int u = -1;
        for (int j = 1; j <= vertices; ++j)
            if (!visited[j] && (u == -1 || dist[j] < dist[u]))
                u = j;
        if (dist[u] == INT_MAX) break;
        visited[u] = true;
        for (auto &[v, w] : graph[u])
            if (dist[u] + w < dist[v])
                dist[v] = dist[u] + w;
    }
    cout << (dist[vertices] == INT_MAX ? -1 : dist[vertices]);
    return 0;
}

Bellman-Ford Algorithm

#include <iostream>
#include <vector>
#include <climits>
using namespace std;

struct Edge { int u, v, weight; };

int main() {
    int vertices, edges, limit;
    cin >> vertices >> edges >> limit;
    vector<Edge> edgeList(edges);
    for (int i = 0; i < edges; ++i)
        cin >> edgeList[i].u >> edgeList[i].v >> edgeList[i].weight;
    vector<int> dist(vertices + 1, INT_MAX);
    dist[1] = 0;
    for (int i = 0; i < limit; ++i) {
        vector<int> prev = dist;
        bool updated = false;
        for (auto &e : edgeList)
            if (prev[e.u] != INT_MAX && prev[e.u] + e.weight < dist[e.v]) {
                dist[e.v] = prev[e.u] + e.weight;
                updated = true;
            }
        if (!updated) break;
    }
    cout << (dist[vertices] == INT_MAX ? "impossible" : to_string(dist[vertices]));
    return 0;
}

SPFA Algorithm

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

int main() {
    int vertices, edges;
    cin >> vertices >> edges;
    vector<vector<pair<int, int>>> graph(vertices + 1);
    while (edges--) {
        int u, v, w;
        cin >> u >> v >> w;
        graph[u].emplace_back(v, w);
    }
    vector<int> dist(vertices + 1, INT_MAX);
    vector<bool> inQueue(vertices + 1, false);
    queue<int> q;
    dist[1] = 0;
    q.push(1);
    inQueue[1] = true;
    while (!q.empty()) {
        int u = q.front(); q.pop();
        inQueue[u] = false;
        for (auto &[v, w] : graph[u])
            if (dist[u] != INT_MAX && dist[u] + w < dist[v]) {
                dist[v] = dist[u] + w;
                if (!inQueue[v]) {
                    q.push(v);
                    inQueue[v] = true;
                }
            }
    }
    cout << (dist[vertices] == INT_MAX ? "impossible" : to_string(dist[vertices]));
    return 0;
}

Floyd-Warshall Algorithm

#include <iostream>
#include <vector>
#include <climits>
using namespace std;

int main() {
    int vertices, edges, queries;
    cin >> vertices >> edges >> queries;
    vector<vector<long long>> dist(vertices + 1, vector<long long>(vertices + 1, LLONG_MAX / 2));
    for (int i = 1; i <= vertices; ++i) dist[i][i] = 0;
    while (edges--) {
        int u, v, w;
        cin >> u >> v >> w;
        dist[u][v] = min(dist[u][v], (long long)w);
    }
    for (int k = 1; k <= vertices; ++k)
        for (int i = 1; i <= vertices; ++i)
            for (int j = 1; j <= vertices; ++j)
                dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j]);
    while (queries--) {
        int u, v;
        cin >> u >> v;
        if (dist[u][v] > LLONG_MAX / 3) cout << "impossible" << endl;
        else cout << dist[u][v] << endl;
    }
    return 0;
}

Prim's Algorithm (Naive)

#include <iostream>
#include <vector>
#include <climits>
using namespace std;

int main() {
    int vertices, edges;
    cin >> vertices >> edges;
    vector<vector<pair<int, int>>> graph(vertices + 1);
    while (edges--) {
        int u, v, w;
        cin >> u >> v >> w;
        graph[u].emplace_back(v, w);
        graph[v].emplace_back(u, w);
    }
    vector<int> minEdge(vertices + 1, INT_MAX);
    vector<bool> inMST(vertices + 1, false);
    minEdge[1] = 0;
    int totalWeight = 0, nodesIncluded = 0;
    for (int i = 0; i < vertices; ++i) {
        int u = -1;
        for (int j = 1; j <= vertices; ++j)
            if (!inMST[j] && (u == -1 || minEdge[j] < minEdge[u]))
                u = j;
        if (minEdge[u] == INT_MAX) break;
        inMST[u] = true;
        totalWeight += minEdge[u];
        ++nodesIncluded;
        for (auto &[v, w] : graph[u])
            if (w < minEdge[v]) minEdge[v] = w;
    }
    cout << (nodesIncluded == vertices ? to_string(totalWeight) : "impossible");
    return 0;
}

Kruskal's Algorithm

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

struct Edge { int u, v, weight; };
vector<int> parent;

int findSet(int x) {
    return parent[x] == x ? x : parent[x] = findSet(parent[x]);
}

int main() {
    int vertices, edges;
    cin >> vertices >> edges;
    vector<Edge> edgeList(edges);
    for (int i = 0; i < edges; ++i)
        cin >> edgeList[i].u >> edgeList[i].v >> edgeList[i].weight;
    sort(edgeList.begin(), edgeList.end(), [](Edge &a, Edge &b) { return a.weight < b.weight; });
    parent.resize(vertices + 1);
    for (int i = 1; i <= vertices; ++i) parent[i] = i;
    int totalWeight = 0, edgesUsed = 0;
    for (auto &e : edgeList) {
        int setU = findSet(e.u), setV = findSet(e.v);
        if (setU != setV) {
            parent[setV] = setU;
            totalWeight += e.weight;
            if (++edgesUsed == vertices - 1) break;
        }
    }
    cout << (edgesUsed == vertices - 1 ? to_string(totalWeight) : "impossible");
    return 0;
}

Greedy Algorithms

Interval Point Selection

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main() {
    int n;
    cin >> n;
    vector<pair<int, int>> intervals(n);
    for (auto &[l, r] : intervals) cin >> l >> r;
    sort(intervals.begin(), intervals.end(), [](auto &a, auto &b) { return a.second < b.second; });
    int points = 0, last = -2e9;
    for (auto &[l, r] : intervals)
        if (last < l) {
            ++points;
            last = r;
        }
    cout << points;
    return 0;
}

Maximum Non-Overlapping Intervals

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main() {
    int n;
    cin >> n;
    vector<pair<int, int>> intervals(n);
    for (auto &[l, r] : intervals) cin >> l >> r;
    sort(intervals.begin(), intervals.end(), [](auto &a, auto &b) { return a.second < b.second; });
    int count = 0, last = -2e9;
    for (auto &[l, r] : intervals)
        if (last < l) {
            ++count;
            last = r;
        }
    cout << count;
    return 0;
}

Interval Grouping

#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;

int main() {
    int n;
    cin >> n;
    vector<pair<int, int>> intervals(n);
    for (auto &[l, r] : intervals) cin >> l >> r;
    sort(intervals.begin(), intervals.end());
    priority_queue<int, vector<int>, greater<int>> minHeap;
    for (auto &[l, r] : intervals) {
        if (minHeap.empty() || minHeap.top() >= l)
            minHeap.push(r);
        else {
            minHeap.pop();
            minHeap.push(r);
        }
    }
    cout << minHeap.size();
    return 0;
}

Interval Coverage

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main() {
    int start, end, n;
    cin >> start >> end >> n;
    vector<pair<int, int>> intervals(n);
    for (auto &[l, r] : intervals) cin >> l >> r;
    sort(intervals.begin(), intervals.end());
    int segments = 0, i = 0;
    bool covered = false;
    while (i < n) {
        int furthest = -2e9, j = i;
        while (j < n && intervals[j].first <= start) {
            furthest = max(furthest, intervals[j].second);
            ++j;
        }
        if (furthest < start) break;
        ++segments;
        start = furthest;
        if (start >= end) { covered = true; break; }
        i = j;
    }
    cout << (covered ? to_string(segments) : "-1");
    return 0;
}

Data Structures

KMP Algorithm

#include <iostream>
#include <string>
#include <vector>
using namespace std;

int main() {
    string pattern, text;
    cin >> pattern >> text;
    int m = pattern.size(), n = text.size();
    vector<int> lps(m, 0);
    for (int i = 1, len = 0; i < m; ) {
        if (pattern[i] == pattern[len]) lps[i++] = ++len;
        else if (len) len = lps[len-1];
        else lps[i++] = 0;
    }
    vector<int> matches;
    for (int i = 0, j = 0; i < n; ) {
        if (text[i] == pattern[j]) { ++i; ++j; }
        if (j == m) {
            matches.push_back(i - j);
            j = lps[j-1];
        } else if (i < n && text[i] != pattern[j]) {
            if (j) j = lps[j-1];
            else ++i;
        }
    }
    for (int pos : matches) cout << pos << ' ';
    return 0;
}

Z-Function

#include <iostream>
#include <string>
#include <vector>
using namespace std;

int main() {
    string pattern, text;
    cin >> pattern >> text;
    string combined = pattern + '#' + text;
    int len = combined.size();
    vector<int> z(len, 0);
    for (int i = 1, l = 0, r = 0; i < len; ++i) {
        if (i <= r) z[i] = min(r - i + 1, z[i - l]);
        while (i + z[i] < len && combined[z[i]] == combined[i + z[i]]) ++z[i];
        if (i + z[i] - 1 > r) { l = i; r = i + z[i] - 1; }
    }
    for (int i = pattern.size() + 1; i < len; ++i)
        if (z[i] == pattern.size()) cout << i - pattern.size() - 1 << ' ';
    return 0;
}

Trie for String Counting

#include <iostream>
#include <string>
#include <vector>
using namespace std;

struct TrieNode {
    vector<TrieNode*> children;
    int count;
    TrieNode() : children(26, nullptr), count(0) {}
};

class Trie {
    TrieNode* root;
public:
    Trie() { root = new TrieNode(); }
    void insert(const string &s) {
        TrieNode* node = root;
        for (char ch : s) {
            int idx = ch - 'a';
            if (!node->children[idx]) node->children[idx] = new TrieNode();
            node = node->children[idx];
        }
        ++node->count;
    }
    int query(const string &s) {
        TrieNode* node = root;
        for (char ch : s) {
            int idx = ch - 'a';
            if (!node->children[idx]) return 0;
            node = node->children[idx];
        }
        return node->count;
    }
};

int main() {
    int n;
    cin >> n;
    Trie trie;
    while (n--) {
        char op; string s;
        cin >> op >> s;
        if (op == 'I') trie.insert(s);
        else cout << trie.query(s) << endl;
    }
    return 0;
}

Union-Find

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

class UnionFind {
    vector<int> parent;
public:
    UnionFind(int n) : parent(n + 1) { for (int i = 1; i <= n; ++i) parent[i] = i; }
    int find(int x) { return parent[x] == x ? x : parent[x] = find(parent[x]); }
    void unite(int a, int b) { parent[find(a)] = find(b); }
    bool connected(int a, int b) { return find(a) == find(b); }
};

int main() {
    int n, m;
    cin >> n >> m;
    UnionFind uf(n);
    while (m--) {
        char op; int a, b;
        cin >> op >> a >> b;
        if (op == 'M') uf.unite(a, b);
        else cout << (uf.connected(a, b) ? "Yes" : "No") << endl;
    }
    return 0;
}

Basic Algorithms

Quick Sort

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

void quickSort(vector<int> &arr, int left, int right) {
    if (left >= right) return;
    int pivot = arr[(left + right) / 2], i = left - 1, j = right + 1;
    while (i < j) {
        do ++i; while (arr[i] < pivot);
        do --j; while (arr[j] > pivot);
        if (i < j) swap(arr[i], arr[j]);
    }
    quickSort(arr, left, j);
    quickSort(arr, j + 1, right);
}

int main() {
    int n;
    cin >> n;
    vector<int> arr(n);
    for (int &x : arr) cin >> x;
    quickSort(arr, 0, n - 1);
    for (int x : arr) cout << x << ' ';
    return 0;
}

Merge Sort

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

void mergeSort(vector<int> &arr, int left, int right) {
    if (left >= right) return;
    int mid = (left + right) / 2;
    mergeSort(arr, left, mid);
    mergeSort(arr, mid + 1, right);
    vector<int> temp(right - left + 1);
    int i = left, j = mid + 1, k = 0;
    while (i <= mid && j <= right)
        temp[k++] = arr[i] <= arr[j] ? arr[i++] : arr[j++];
    while (i <= mid) temp[k++] = arr[i++];
    while (j <= right) temp[k++] = arr[j++];
    for (int idx = 0; idx < k; ++idx) arr[left + idx] = temp[idx];
}

int main() {
    int n;
    cin >> n;
    vector<int> arr(n);
    for (int &x : arr) cin >> x;
    mergeSort(arr, 0, n - 1);
    for (int x : arr) cout << x << ' ';
    return 0;
}

Dynamic Programing

0/1 Knapsack

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

int main() {
    int items, capacity;
    cin >> items >> capacity;
    vector<int> dp(capacity + 1, 0);
    while (items--) {
        int weight, value;
        cin >> weight >> value;
        for (int w = capacity; w >= weight; --w)
            dp[w] = max(dp[w], dp[w - weight] + value);
    }
    cout << dp[capacity];
    return 0;
}

Unbounded Knapsack

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

int main() {
    int items, capacity;
    cin >> items >> capacity;
    vector<int> dp(capacity + 1, 0);
    while (items--) {
        int weight, value;
        cin >> weight >> value;
        for (int w = weight; w <= capacity; ++w)
            dp[w] = max(dp[w], dp[w - weight] + value);
    }
    cout << dp[capacity];
    return 0;
}

Bounded Knapsack with Binary Optimization

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

int main() {
    int items, capacity;
    cin >> items >> capacity;
    vector<pair<int, int>> goods;
    while (items--) {
        int weight, value, count;
        cin >> weight >> value >> count;
        for (int k = 1; k <= count; k *= 2) {
            count -= k;
            goods.emplace_back(weight * k, value * k);
        }
        if (count > 0) goods.emplace_back(weight * count, value * count);
    }
    vector<int> dp(capacity + 1, 0);
    for (auto &[w, v] : goods)
        for (int j = capacity; j >= w; --j)
            dp[j] = max(dp[j], dp[j - w] + v);
    cout << dp[capacity];
    return 0;
}

Group Knapsack

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

int main() {
    int capacity, groups;
    cin >> capacity >> groups;
    vector<vector<pair<int, int>>> groupItems(groups + 1);
    for (int g = 1; g <= groups; ++g) {
        int count;
        cin >> count;
        while (count--) {
            int weight, value;
            cin >> weight >> value;
            groupItems[g].emplace_back(weight, value);
        }
    }
    vector<int> dp(capacity + 1, 0);
    for (int g = 1; g <= groups; ++g)
        for (int w = capacity; w >= 0; --w)
            for (auto &[weight, value] : groupItems[g])
                if (w >= weight)
                    dp[w] = max(dp[w], dp[w - weight] + value);
    cout << dp[capacity];
    return 0;
}

Knapsack with Count of Optimal Solutions

#include <iostream>
#include <vector>
using namespace std;
const int MOD = 1e9 + 7;

int main() {
    int items, capacity;
    cin >> items >> capacity;
    vector<int> maxValue(capacity + 1, 0), ways(capacity + 1, 1);
    while (items--) {
        int weight, value;
        cin >> weight >> value;
        for (int w = capacity; w >= weight; --w) {
            int newValue = maxValue[w - weight] + value;
            if (newValue > maxValue[w]) {
                maxValue[w] = newValue;
                ways[w] = ways[w - weight];
            } else if (newValue == maxValue[w])
                ways[w] = (ways[w] + ways[w - weight]) % MOD;
        }
    }
    cout << ways[capacity];
    return 0;
}

Reconstructing Knapsack Solution

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

int main() {
    int items, capacity;
    cin >> items >> capacity;
    vector<int> weight(items + 1), value(items + 1);
    for (int i = 1; i <= items; ++i) cin >> weight[i] >> value[i];
    vector<vector<int>> dp(items + 2, vector<int>(capacity + 1, 0));
    for (int i = items; i >= 1; --i)
        for (int w = 0; w <= capacity; ++w) {
            dp[i][w] = dp[i + 1][w];
            if (w >= weight[i])
                dp[i][w] = max(dp[i][w], dp[i + 1][w - weight[i]] + value[i]);
        }
    vector<int> selection;
    for (int i = 1, w = capacity; i <= items; ++i)
        if (w >= weight[i] && dp[i][w] == dp[i + 1][w - weight[i]] + value[i]) {
            selection.push_back(i);
            w -= weight[i];
        }
    for (int idx : selection) cout << idx << ' ';
    return 0;
}

Tags: algorithms C++ number-theory graph-theory greedy

Posted on Sat, 13 Jun 2026 17:12:21 +0000 by sebjlan