整数分解(划分)

整数分解(划分)

分解和

· 给定一个整数n,找到k个数,使得其和等于n。

样例:

4 = 1+1+1+1
4 = 1+1+2
4 = 1+3
4 = 2+2
4 = 4

求其分解的所有可能,并输出分解表达式。

思路:要拆分整数n,肯定先要找到一个元素,然后我们会发现,剩下的问题还是一个整数分解问题,因此容易得到问题的解。

定义函数 f(n) 为 n 可以拆分的解的个数,即可以先拆分出一个数字k ( k = 1,2,……,n),然后再拆分 f(k) ,可以得出有:

n = 1+f(n-1); 
n = 2+f(n-2); 
.....
n = (n-1)+f(1); 
n = n+f(0);`

再来想一想该用怎样的数据结构来存储,很明显用数组int res[max] 用来暂存拆分元素

数据存储

先拿简单的拆分来说事,拆分成两个数的情况。

//只拆分为两个数的时候
void resolve(int n)
{ 
    //res用来暂存拆分元素
    //p是游标,初始值为p=0;
    for(int i=1;i<=n;i++)
    {
        res[p]=i;
        p++;//下一个位置存储n-i;
        res[p]=n-i;
        //输出处理
        p--;//回归到起点。
    }
}

分析上面的代码,再来看递推,如果分成三个数,那么在即将执行 res[p] = n - i 时,需要将 n - i 在一次分解成两个数,即 resolve( n - i ),这样就形成了递归
那么递归的出口条件是什么呢,当需要分解的数是0时,已经不能在继续往下分了,当进入递归出口的时候,表明本次已经分解完成,可以输出res中的数据。

void resolve(int n)
{ 
    if(n<=0)
    {   
        for (int i=0; i<p_res; i++)  //输出 
            cout << res[i] << " ";  
        cout << endl;  
        return ;
    }
    for(int i=1;i<=n;i++)
    {
        res[p]=i;
        p++;
        resolve(n-i);
        p--;
    }
}

但这还有个问题,如当n=4时,会输出1 3,和3 1两组解,其实他们是相同的。

如果要求答案不能重复呢?

同样,我们可以定义一个函数f(n, min_factor),其中min_factor表示n拆分后元素中的最小值,这样即可通过min_factor来限制for循环的初始值达到拆分元素从小到大输出的目的,从而避免相同的解重复输出
贴出完整可运行代码如下:

#include <iostream>  
using namespace std;   
#define MAX 20  
int res_num;  
// 拆分元素暂存在res数组中  
int res[MAX];  
int p = 0;  
// 将n进行拆分 
void resolve(int n, int min_factor=1);  
int main() {  
    while (1) {  
        int n;  
        cin >> n;  
        resolve(n,1);  
        cout << "total num of res:\t" << res_num << endl;  
        res_num = 0;  
    }  
    return 0;  
}  
void resolve(int n, int min_factor) {  
    if (n<=0) { // 出口  
        for (int i=0; i<p; i++)  
            cout << res[i] << " ";  
        cout << endl;  
        res_num++;  
    }  

    for (int i=min_factor; i<=n; i++) {     // 此处修改  
        res[p] = i;  
        p++;            // p++ 来顺序存储各个拆分元素  
        resolve(n-i, i);// 此处修改  
        p--;            // 此行必须有,执行完这一行,下一次for循环才能回退  
    }  
}  

分解积

· 将一个数n的分解为因子的乘积形式,输出所有可能,并输出表达式。

12 = 2*2*3;
12 = 2*6;
12 = 3*4;
12 = 6*2;
12 = 12*1;

解法与上述大同小异,不再赘述。

#include<iostream>
using namespace std;
int data[100];
int p=0;
int num=0; 
int x;
void resolve(int n,int min)
{
    if(n<2) 
    {
        num++;
        cout<<x<<"=";
        for(int j=0;j<p;j++)
        {
            cout<<data[j];
            if(j!=p-1)
            cout<<"*";
            if(data[j]==x)
            cout<<"*1";
        }
        cout<<endl;
        return ;
    }
    for(int i=min;i<=n;i++)
    {
        if(n%i==0)
        {
            data[p]=i;
            p++; 
            resolve(n/i,i);
            p--;        
        }
    }
}
int main()
{
        while(cin>>x)
        {
            resolve(x,2);
            cout<<"The totla num is  "<<num<<endl;
            cout<<"--------------------------"<<endl;
        }
}

动态规划之整数划分

整数划分: 指把一个正整数n写成多个大于等于1且小于等于其本身的整数的和,则其中各加数所构成的集合为n的一个划分。这是一个典型的递归算法

1、问题描述和分析

对于一个正整数n的分划,就是把n表示成一系列正整数之和的表达式。

注意,分划与顺序无关,例如6=1+5 和 6=5+1被认为是同一个划分另外,这个整数n本身也算是一种分化。
分析:
所谓整数划分,是指把一个正整数n写成为

\[n=m_1+m_2+\cdots +m_i \]

其中,mi为正整数,并且imgimg 为n的一个划分。

如果img 中的最大值不超过m,即img ,则称它属于n的一个m划分。

例如:当n=4时,他有5个划分:{4}, {3,1}, {2,2}, {2,1,1}, {1,1,1,1};

2、数据结构和算法

该问题是求出n的所有划分个数,即f(n, m)。下面我们考虑求f(n,m)的方法,采用递归法, 根据n和m的关系,考虑以下几种情况:
(1) 当n=1时,不论m的值为多少(m>0),只有一种划分即{1};
(2) 当m=1时,不论n的值为多少,只有一种划分即n个1,{1,1,1,…,1};
(3) 当n=m时,根据划分中是否包含n,可以分为两种情况:
(a) 划分中包含n的情况,只有一个即{n}
(b) 划分中不包含n的情况,这时划分中最大的数字也一定比n小即n的所有(n-1)划分
因此 f(n,n) =1 + f(n,n-1);
(4) 当n<m时,由于划分中不可能出现负数,因此就相当于f(n,n);
(5) 但n>m时,根据划分中是否包含最大值m,可以分为两种情况:
(a) 划分中包含m的情况,即{m, {x1,x2,…xi}}, 其中{x1,x2,… xi}和为n-m,因此这情况下为f(n-m,m);
(b) 划分中不包含m的情况,则划分中所有值都比m小,即n的(m-1)划分(离散性),个数为f(n,m-1);
因此 f(n, m) = f(n-m, m)+f(n,m-1);

image-20210818212659859

#include<stdio.h>
int Divintege(int n,int m)
{
    if(n==1||m==1)
        return 1;
    else if(n<m)
        return Divintege(n,n);
    else if(n==m)
        return 1+Divintege(n,n-1);
    else
        return Divintege(n,m-1)+Divintege(n-m,m);
}
int main(void)
{
    int n;

    while(scanf("%d",&n)!=EOF&&(n>=1))
    {
        printf("%d\n",Divintege(n,n));
    }

    return 0;
}

说明

转载自(有删改):整数分解方法_casion-CSDN博客_整数拆分公式

如有侵权请联系博主删除

posted @ 2021-08-18 21:37  Exstory  阅读(2989)  评论(1编辑  收藏  举报