You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求可分批次生成n选k组合的快速算法(支持C/C++/CUDA/Matlab)

Great question—when dealing with combinatorial problems at scale like n=250, k=6 (where total combinations hit ~3.19e11), full in-memory storage is completely infeasible. Iterative batch generation—producing x combinations at a time, using the last combination of a batch as the starting point for the next—is the only practical solution. Below are efficient, actionable implementations for C/C++, CUDA, and Matlab tailored to your use case:


Core Concept: Incremental Combination Generation

All solutions rely on generating combinations one at a time in lexicographical order (or via rank/unrank for parallelism), so you never need to store more than a single combination (plus batch metadata) in memory. The key is avoiding recursive approaches (which suffer from stack overhead and scalability limits) and using iterative logic to jump from one valid combination to the next.


C/C++ Implementation

Lexicographical next-combination is ideal here—it’s fast, memory-light, and easy to adapt for batching.

Next-Combination Utility Function

This function takes a current combination (sorted array of indices, 0-based) and modifies it to the next valid combination in lex order. It returns false when there are no more combinations left.

#include <vector>
#include <functional>

bool next_combination(std::vector<int>& comb, int n) {
    const int k = comb.size();
    int i = k - 1;

    // Find the first position that can be incremented
    while (i >= 0 && comb[i] == n - k + i) {
        i--;
    }
    if (i < 0) return false; // No more combinations

    // Increment this position and reset subsequent elements to the smallest valid values
    comb[i]++;
    for (int j = i + 1; j < k; j++) {
        comb[j] = comb[j-1] + 1;
    }
    return true;
}

Batch Generation Logic

Use this to generate x combinations starting from a given initial combination, processing each as you go (e.g., running your set coverage calculations):

void generate_batch(std::vector<int>& start_comb, int n, int batch_size, 
                    const std::function<void(const std::vector<int>&)>& process) {
    std::vector<int> current = start_comb;
    int count = 0;

    do {
        process(current); // Replace with your set coverage logic
        count++;
        if (count >= batch_size) break;
    } while (next_combination(current, n));

    // Update start_comb to the last generated combination for the next batch
    start_comb = current;
}

Optimization: For k=6, storing combinations as a small array of integers is already extremely memory-efficient (each combination is just 24 bytes). You can further optimize by using bitmasks (e.g., std::bitset<250>) if your set coverage logic benefits from bitwise operations.


CUDA Parallel Implementation

For massive throughput, use GPU parallelism with rank/unrank algorithms—these let you directly compute the combination corresponding to a given position (rank) in the lex order, so you can split the total combination space into chunks and assign each chunk to a GPU thread block.

Precompute Combination Counts

First, precompute all needed binomial coefficients C(m, t) (for t from 0 to 6, m from 0 to 250) and copy them to the GPU. These are used to map ranks to combinations.

#include <cstdint>
#include <vector>

// Precompute C(m, t) for m up to 250, t up to 6
std::vector<uint64_t> precompute_comb_counts() {
    std::vector<uint64_t> counts(251 * 7, 0);
    // Base case: C(m, 0) = 1 for all m
    for (int m = 0; m <= 250; m++) counts[m*7 + 0] = 1;
    for (int t = 1; t <= 6; t++) {
        for (int m = t; m <= 250; m++) {
            counts[m*7 + t] = counts[(m-1)*7 + t-1] + counts[(m-1)*7 + t];
        }
    }
    return counts;
}

GPU Kernel for Batch Generation

Each thread generates one combination, using the precomputed counts to convert a rank to a valid combination:

__global__ void generate_combinations(uint64_t start_rank, uint64_t end_rank, int n, int k, 
                                      const uint64_t* comb_counts, int* results) {
    uint64_t rank = start_rank + blockIdx.x * blockDim.x + threadIdx.x;
    if (rank >= end_rank) return;

    int comb[6]; // k=6, fixed size for efficiency
    uint64_t remaining = rank;
    int prev = -1;

    for (int i = 0; i < k; i++) {
        int t = k - i - 1;
        int m = n - prev - 1;
        // Find the largest c where C(m - c - 1, t) <= remaining
        int c = 0;
        while (c < m - t && comb_counts[(m - c - 1)*7 + t] <= remaining) {
            c++;
        }
        comb[i] = prev + 1 + c;
        remaining -= comb_counts[(m - c - 1)*7 + t];
        prev = comb[i];
    }

    // Write the combination to output memory
    int idx = (rank - start_rank) * k;
    for (int i = 0; i < k; i++) {
        results[idx + i] = comb[i];
    }
}

Usage: Split the total rank range (0 to C(250,6)-1) into batches, launch the kernel for each batch, and process the results on the GPU or copy them back to the CPU.


Matlab Implementation

Matlab’s built-in nchoosek generates all combinations at once, which is useless for your scale. Instead, implement an iterative next-combination function or use rank/unrank for batch generation.

Iterative Next-Combination Function

function [comb, has_next] = next_combination(comb, n)
    k = length(comb);
    i = k;
    % Find the first position that can be incremented
    while i >= 1 && comb(i) == n - k + i
        i = i - 1;
    end
    if i < 1
        has_next = false;
        return;
    end
    % Update the combination
    comb(i) = comb(i) + 1;
    for j = i+1:k
        comb(j) = comb(j-1) + 1;
    end
    has_next = true;
end

Batch Generation Logic

function start_comb = generate_batch(start_comb, n, batch_size, process_func)
    current = start_comb;
    count = 0;
    while count < batch_size
        process_func(current); % Replace with your set coverage logic
        count = count + 1;
        [current, has_next] = next_combination(current, n);
        if ~has_next
            break;
        end
    end
    start_comb = current; % Pass back the last combination for the next batch
end

Rank/Unrank Alternative: For faster batch jumps, precompute binomial coefficients with nchoosek and implement an unrank function to directly generate combinations from a given rank, similar to the CUDA approach.


Key Optimization Tips

  1. Precompute Binomial Coefficients: This eliminates redundant calculations for rank/unrank operations and speeds up next-combination checks.
  2. Avoid Full Storage: Always process combinations immediately after generating them—never store more than a single batch (or even a single combination) in memory.
  3. Parallelize Where Possible: Use CUDA or multi-threaded C++ to process multiple combinations simultaneously, leveraging hardware acceleration for your set coverage calculations.

内容的提问来源于stack exchange,提问作者proczell

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 06:49:22