整数划分问题

整数划分是将一个正整数n表示为一系列正整数之和的问题。顺序不同的划分视为相同的划分。这是一个经典的组合数学和计算机科学问题。

1. 问题定义

将正整数n表示为:

n = a₁ + a₂ + ... + aₖ (aᵢ ≥ 1, 1 ≤ i ≤ k)

其中划分的顺序不重要,即 3+2 和 2+3 被视为相同的划分。

2. 递推关系

设 p(n, m) 表示将整数n划分成最大加数不超过m的划分个数。

递推关系:

  • p(n, 1) = 1 (只有全1的划分)

  • p(1, m) = 1 (只有1本身)

  • p(n, m) = p(n, n) 当 m > n

  • p(n, m) = p(n, m-1) + p(n-m, m) 当 n > m ≥ 1

3. C语言实现

方法一:递归实现

cpp 复制代码
#include <stdio.h>

// 递归计算整数划分
int partition_recursive(int n, int m) {
    if (n < 1 || m < 1) return 0;
    if (n == 1 || m == 1) return 1;
    if (n < m) return partition_recursive(n, n);
    if (n == m) return 1 + partition_recursive(n, m - 1);
    return partition_recursive(n, m - 1) + partition_recursive(n - m, m);
}

int main() {
    int n;
    printf("请输入要划分的整数 n: ");
    scanf("%d", &n);
    
    printf("整数 %d 的划分数: %d\n", n, partition_recursive(n, n));
    return 0;
}

方法二:动态规划

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>

// 动态规划计算整数划分
int partition_dp(int n) {
    if (n <= 0) return 0;
    
    int **dp = (int**)malloc((n + 1) * sizeof(int*));
    for (int i = 0; i <= n; i++) {
        dp[i] = (int*)malloc((n + 1) * sizeof(int));
    }
    
    // 初始化
    for (int i = 0; i <= n; i++) {
        for (int j = 0; j <= n; j++) {
            if (i == 0 || j == 0) {
                dp[i][j] = 0;
            } else if (i == 1 || j == 1) {
                dp[i][j] = 1;
            } else if (i < j) {
                dp[i][j] = dp[i][i];
            } else if (i == j) {
                dp[i][j] = 1 + dp[i][j - 1];
            } else {
                dp[i][j] = dp[i][j - 1] + dp[i - j][j];
            }
        }
    }
    
    int result = dp[n][n];
    
    // 释放内存
    for (int i = 0; i <= n; i++) {
        free(dp[i]);
    }
    free(dp);
    
    return result;
}

int main() {
    int n;
    printf("请输入要划分的整数 n: ");
    scanf("%d", &n);
    
    printf("整数 %d 的划分数: %d\n", n, partition_dp(n));
    return 0;
}

方法三:优化的动态规划(一维数组)

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>

// 优化的动态规划(使用一维数组)
int partition_dp_optimized(int n) {
    if (n <= 0) return 0;
    
    int *dp = (int*)malloc((n + 1) * sizeof(int));
    
    // 初始化
    dp[0] = 1;  // 空划分算一种
    
    for (int i = 1; i <= n; i++) {
        dp[i] = 0;
    }
    
    // 动态规划计算
    for (int i = 1; i <= n; i++) {
        for (int j = i; j <= n; j++) {
            dp[j] += dp[j - i];
        }
    }
    
    int result = dp[n];
    free(dp);
    return result;
}

int main() {
    int n;
    printf("请输入要划分的整数 n: ");
    scanf("%d", &n);
    
    printf("整数 %d 的划分数: %d\n", n, partition_dp_optimized(n));
    return 0;
}

4. 输出所有划分

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>

// 输出所有整数划分
void print_partitions(int n, int max, int *arr, int index) {
    if (n == 0) {
        // 找到一个划分,输出
        for (int i = 0; i < index; i++) {
            printf("%d", arr[i]);
            if (i < index - 1) printf(" + ");
        }
        printf("\n");
        return;
    }
    
    for (int i = max; i >= 1; i--) {
        if (n >= i) {
            arr[index] = i;
            print_partitions(n - i, i, arr, index + 1);
        }
    }
}

int main() {
    int n;
    printf("请输入要划分的整数 n: ");
    scanf("%d", &n);
    
    int *arr = (int*)malloc(n * sizeof(int));
    
    printf("整数 %d 的所有划分:\n", n);
    print_partitions(n, n, arr, 0);
    
    free(arr);
    return 0;
}

5. 计算并输出所有划分(带计数)

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>

int count = 0;

// 输出所有划分并计数
void print_and_count_partitions(int n, int max, int *arr, int index) {
    if (n == 0) {
        count++;
        printf("%d: ", count);
        for (int i = 0; i < index; i++) {
            printf("%d", arr[i]);
            if (i < index - 1) printf(" + ");
        }
        printf("\n");
        return;
    }
    
    for (int i = max; i >= 1; i--) {
        if (n >= i) {
            arr[index] = i;
            print_and_count_partitions(n - i, i, arr, index + 1);
        }
    }
}

int main() {
    int n;
    printf("请输入要划分的整数 n: ");
    scanf("%d", &n);
    
    int *arr = (int*)malloc(n * sizeof(int));
    count = 0;
    
    printf("整数 %d 的所有划分:\n", n);
    print_and_count_partitions(n, n, arr, 0);
    printf("总划分数: %d\n", count);
    
    free(arr);
    return 0;
}

6. 完整测试程序

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

// 递归方法
int partition_recursive(int n, int m) {
    if (n < 1 || m < 1) return 0;
    if (n == 1 || m == 1) return 1;
    if (n < m) return partition_recursive(n, n);
    if (n == m) return 1 + partition_recursive(n, m - 1);
    return partition_recursive(n, m - 1) + partition_recursive(n - m, m);
}

// 动态规划方法
int partition_dp(int n) {
    if (n <= 0) return 0;
    
    int **dp = (int**)malloc((n + 1) * sizeof(int*));
    for (int i = 0; i <= n; i++) {
        dp[i] = (int*)malloc((n + 1) * sizeof(int));
    }
    
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) {
            if (i == 1 || j == 1) {
                dp[i][j] = 1;
            } else if (i < j) {
                dp[i][j] = dp[i][i];
            } else if (i == j) {
                dp[i][j] = 1 + dp[i][j - 1];
            } else {
                dp[i][j] = dp[i][j - 1] + dp[i - j][j];
            }
        }
    }
    
    int result = dp[n][n];
    
    for (int i = 0; i <= n; i++) {
        free(dp[i]);
    }
    free(dp);
    
    return result;
}

// 优化的动态规划
int partition_dp_optimized(int n) {
    if (n <= 0) return 0;
    
    int *dp = (int*)malloc((n + 1) * sizeof(int));
    dp[0] = 1;
    
    for (int i = 1; i <= n; i++) {
        dp[i] = 0;
    }
    
    for (int i = 1; i <= n; i++) {
        for (int j = i; j <= n; j++) {
            dp[j] += dp[j - i];
        }
    }
    
    int result = dp[n];
    free(dp);
    return result;
}

int main() {
    int n;
    printf("整数划分问题测试\n");
    printf("请输入要划分的整数 n: ");
    scanf("%d", &n);
    
    if (n <= 0) {
        printf("请输入正整数\n");
        return 1;
    }
    
    printf("\n方法比较:\n");
    
    // 测试递归方法(只适用于小n)
    if (n <= 30) {
        clock_t start = clock();
        int result_rec = partition_recursive(n, n);
        clock_t end = clock();
        double time_rec = ((double)(end - start)) / CLOCKS_PER_SEC;
        printf("递归方法: %d (耗时: %.6f秒)\n", result_rec, time_rec);
    } else {
        printf("递归方法: n太大,跳过计算\n");
    }
    
    // 测试动态规划
    clock_t start = clock();
    int result_dp = partition_dp(n);
    clock_t end = clock();
    double time_dp = ((double)(end - start)) / CLOCKS_PER_SEC;
    printf("动态规划: %d (耗时: %.6f秒)\n", result_dp, time_dp);
    
    // 测试优化的动态规划
    start = clock();
    int result_opt = partition_dp_optimized(n);
    end = clock();
    double time_opt = ((double)(end - start)) / CLOCKS_PER_SEC;
    printf("优化动态规划: %d (耗时: %.6f秒)\n", result_opt, time_opt);
    
    return 0;
}

7. 编译和运行

bash 复制 下载

复制代码
gcc integer_partition.c -o integer_partition
./integer_partition

8. 算法分析

方法 时间复杂度 空间复杂度 适用场景
递归 O(2ⁿ) O(n) 小规模数据 (n < 30)
动态规划 O(n²) O(n²) 中等规模数据
优化动态规划 O(n²) O(n) 推荐,适合大多数情况
相关推荐
程序员-King.5 小时前
day158—回溯—全排列(LeetCode-46)
算法·leetcode·深度优先·回溯·递归
月挽清风6 小时前
代码随想录第七天:
数据结构·c++·算法
小O的算法实验室6 小时前
2026年AEI SCI1区TOP,基于改进 IRRT*-D* 算法的森林火灾救援场景下直升机轨迹规划,深度解析+性能实测
算法·论文复现·智能算法·智能算法改进
小郭团队7 小时前
2_1_七段式SVPWM (经典算法)算法理论与 MATLAB 实现详解
嵌入式硬件·算法·硬件架构·arm·dsp开发
充值修改昵称7 小时前
数据结构基础:从二叉树到多叉树数据结构进阶
数据结构·python·算法
Deepoch7 小时前
Deepoc数学大模型:发动机行业的算法引擎
人工智能·算法·机器人·发动机·deepoc·发动机行业
浅念-8 小时前
C语言小知识——指针(3)
c语言·开发语言·c++·经验分享·笔记·学习·算法
Hcoco_me8 小时前
大模型面试题84:是否了解 OpenAI 提出的Clip,它和SigLip有什么区别?为什么SigLip效果更好?
人工智能·算法·机器学习·chatgpt·机器人
BHXDML8 小时前
第九章:EM 算法
人工智能·算法·机器学习
却道天凉_好个秋9 小时前
目标检测算法与原理(三):PyTorch实现迁移学习
pytorch·算法·目标检测