求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
- Sorting: We start by sorting the input set to establish a consistent order for our logic.
- Recursive Group Building: The
generate_groupsfunction finds the first unused element, which must start the next group—this prevents permuting group order. - Backtracking: We mark elements as used when adding them to a group, then unmark them after recursion to explore other valid combinations.
- Sorted Groups: We only add elements that come after the last element in the current group, ensuring each group stays in ascending order.
- Printing: The
print_groupingfunction 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
相关产品推荐
相关产品推荐

