整数划分

前几天找到一个有意思的题目
要求是键盘中输入一个数字,然后在屏幕上输出它所有的划分情况,例如:
input : 4

output:
4 = 4;
4 = 3 + 1;
4 = 2 + 2;
4 = 2 + 1 + 1;
4 = 1 + 1 + 1 + 1;

查了百度后发现是acm中的整数划分问题的变形,原题是计算出有多少种分法。

对于我来说,即便知道了acm的算法,解出此题还是有些困难的,毕竟分的数量

只需用一个变量记住递归次数就好,但真正要把结果打印在屏幕上要考虑的因素
要多的多(比如每一行要有个 x = a + b+.... 用递归就感觉有些麻烦了  )

于是我想改变下思路:
用数组去接收每一次划分的方法,划分完成后再依次输出数组中的值从而实现屏幕输出效果。


1. 将数据逐层划分,直到分成x = 1 +1 +......为止
例如: 6 = 5 + 1
           6 = 4 +1 + 1
           6 = 4 + 2
           6 = 3 .........
            ...........   
           6 = 1........


2. 在针对每一层进行处理:
分别求出它们的最大以及最小划分长度
例如:  针对 以4 打头的那一层:
            当其余加数全部为1 的时候,数组达到最长划分长度
            当其余加数的数目尽可能少,数组达到最短划分长度
            (注意:其余的加数不能够大于打头的数字)

 3. 对最长划分长度数组进行操作,将数组中最后一个值加到数组中的第二个位置,
后将最后一个数销毁,从而得到一个新的划分方式
例如:a[0] = 4, a[1] = 1, a[2] = 1
           将a[2]加到a[1]中, 并将a[2]销毁
           得到一个新的划分方式a[0] = 4, a[1] = 2
           (注意:同样的a[1]不能够大于a[0],因此第二个位置其实是相对位置,如果a[1]==a[0]
            那么相应的尾巴上的数应该加到a[2]上)

4. 重复步骤三,每划分一次输出一次,直到数组长度缩减到
最短划分长度,一次循环函数结束
(当达到最短划分长度时,数据已经无法再细分,要结束这层的循环进入下一次的迭代)

OK,弄清楚思路以后解题就方便了:


#include <stdio.h>
#include <stdlib.h>
#define N 100
// 计算数组长度
int len_of_a(int a[])
{
    int i;
    for(i = 1; a[i] != '\0';)
    {
        i++;
    }
    return i;
}

// 输出一种划分方法
void my_output(int a[],int sizeof_a)
{
    //数组, sizeof_a = 数组长度
    int i;
    printf("%d", a[0]);
    for(i = 1; i< sizeof_a; i++)
    {
        printf("+%d", a[i]);
    }
    printf("\n");
}

// 比较现在数组长度,如果大于最短长度则继续缩短数组长度
void my_compare(int k, int less_len, int a[])
{
    //k = 数组长度, less_len = 最小长度, 数组
    int z = 1;
    while(k > less_len)
    {
        if(a[z] < a[0])
        {
            a[z] += a[k-1];
            a[k-1] = '\0';
            k--;
        }
        else
        {
            z++;
            a[z] += a[k-1];
            a[k-1] = '\0';
            k--;
        }
        my_output(a, k);
    }
}

// 整数划分
void my_divide(int number)
{
    int sum = 0;
    int a[N];
    int k ;//数组下标
    int i = number - 1;
    for(i = number - 1; i >= 1; i--)
    {
        //强行锁定数组第一个元素
        a[0] = i;
        for(k = 1; (sum += a[k-1]) != number; k++)
        {
            //确定数组最长长度为k,即把数字分成 number = i +1 +1 +1 +.....+1的形式
            a[k] = 1; 
        }
        //终止符       
        a[k] = '\0';
        //记录数组最短长度
        int less_len;
        if(number % i == 0)
        {
            less_len = number / i;
        }
        else
        {
            less_len = (number / i) + 1;
        }

        //计算数组得到最长长度
        k = len_of_a(a);
        my_output(a,k);
        my_compare(k, less_len, a);
        sum = 0;
    }
}

int main()
{
    int n;
    scanf("%d", &n);
    my_divide(n);
    return 0;
}


(程序我还没有系统地整理过,函数的命名以及一些地方备注,算法的优化,输出格式后续会慢慢修改,
主要先把思路记录下来)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值