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

求C语言实现n元素无重复k/m分组组合生成方案

Generate Unique Groupings of a Set into k-Sized Groups (C Implementation)

Alright, let's break down how to solve this problem. The core challenge is to avoid duplicate groupings—this means we don't consider different orderings of groups (e.g., {0,1}{2,3} is the same as {2,3}{0,1}) or different orderings within a group (e.g., {1,0} is the same as {0,1}) as distinct.

Key Strategy to Avoid Duplicates

To eliminate duplicates, we'll enforce two critical rules during generation:

  • Group elements are sorted: Each group will always be in ascending order, so we never generate reversed groups like {1,0}.
  • Group order is fixed by first element: We always start a new group with the smallest unused element. This ensures we never generate permutations of the same grouping (like swapping {0,1} and {2,3}).

C Code Implementation

Here's a complete, commented implementation that generates and prints all valid unique groupings:

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

#define MAX_ELEMENTS 100

// Global variables for simplicity (you can wrap these in a struct for cleaner code)
int* elements;
int n;
int k;
bool used[MAX_ELEMENTS];
int current_group[MAX_ELEMENTS];
int current_group_size;

// Helper function to print the current grouping (called when all elements are processed)
void print_grouping() {
    printf("{");
    bool first_group = true;
    int remaining_start = -1;

    // Print all complete k-sized groups
    for (int i = 0; i < n; i++) {
        if (used[i]) {
            if (remaining_start == -1) {
                if (!first_group) printf("}{");
                first_group = false;
                remaining_start = i;
            }
            printf("%d", elements[i]);
            // Check if we've reached the end of a k-sized group
            if ((i - remaining_start + 1) == k) {
                remaining_start = -1;
            } else if (i < n-1 && used[i+1]) {
                printf(",");
            }
        }
    }

    // Print remaining single-element groups
    for (int i = 0; i < n; i++) {
        if (!used[i]) {
            if (!first_group) printf("}{");
            first_group = false;
            printf("%d", elements[i]);
        }
    }
    printf("}\n");
}

// Recursive function to build groups
void generate_groups() {
    // Find the first unused element (this will start our next group)
    int first_unused = -1;
    for (int i = 0; i < n; i++) {
        if (!used[i]) {
            first_unused = i;
            break;
        }
    }

    // Base case: all elements are used, print the grouping
    if (first_unused == -1) {
        print_grouping();
        return;
    }

    // If current group is empty, we must add the first unused element (enforces group order rule)
    if (current_group_size == 0) {
        current_group[current_group_size++] = first_unused;
        used[first_unused] = true;
    }

    // If we haven't filled the current group yet
    if (current_group_size < k) {
        // Add elements that come after the last element in current group (enforces sorted group rule)
        for (int i = current_group[current_group_size - 1] + 1; i < n; i++) {
            if (!used[i]) {
                current_group[current_group_size++] = i;
                used[i] = true;
                generate_groups();
                // Backtrack
                used[i] = false;
                current_group_size--;
            }
        }
    } else {
        // Current group is full: save its elements, reset it, and recurse
        int temp_group[MAX_ELEMENTS];
        int temp_size = current_group_size;
        for (int i = 0; i < temp_size; i++) {
            temp_group[i] = current_group[i];
        }
        current_group_size = 0;
        generate_groups();
        // Backtrack: unmark elements in the completed group
        for (int i = 0; i < temp_size; i++) {
            used[temp_group[i]] = false;
        }
        current_group_size = temp_size;
        return;
    }

    // Backtrack: unmark the first element added to the current group
    used[current_group[--current_group_size]] = false;
}

int compare_ints(const void* a, const void* b) {
    return (*(int*)a - *(int*)b);
}

int main() {
    // Example input: S = {0,1,2,3,4}, k=2
    elements = malloc(5 * sizeof(int));
    elements[0] = 0;
    elements[1] = 1;
    elements[2] = 2;
    elements[3] = 3;
    elements[4] = 4;
    n = 5;
    k = 2;

    // Sort elements first (critical for duplicate-avoidance rules)
    qsort(elements, n, sizeof(int), compare_ints);

    // Initialize state
    for (int i = 0; i < n; i++) used[i] = false;
    current_group_size = 0;

    printf("All unique groupings:\n");
    generate_groups();

    free(elements);
    return 0;
}

How It Works

  1. Sorting: We start by sorting the input set to establish a consistent order for our logic.
  2. Recursive Group Building: The generate_groups function finds the first unused element, which must start the next group—this prevents permuting group order.
  3. Backtracking: We mark elements as used when adding them to a group, then unmark them after recursion to explore other valid combinations.
  4. Sorted Groups: We only add elements that come after the last element in the current group, ensuring each group stays in ascending order.
  5. Printing: The print_grouping function outputs complete k-sized groups first, followed by any remaining single-element groups.

Example Output

For the input set {0,1,2,3,4} and k=2, the output will be:

All unique groupings:
{0,1}{2,3}{4}
{0,1}{2,4}{3}
{0,2}{1,3}{4}
{0,2}{1,4}{3}
{0,3}{1,2}{4}
{0,3}{1,4}{2}
{0,4}{1,2}{3}
{0,4}{1,3}{2}

Notice none of these are duplicates—each grouping is unique when ignoring group order and element order within groups.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 03:58:02