• 自然数的拆分


    题目链接  洛谷2404

    【问题描述】自然数的拆分:任何一个大于1的自然数N,
    总可以拆分成若干个自然数之和,并且有多种拆分方法。试求 n的所有拆分。
    例如自然数5,可以有如下一些拆分方法:
    5=1+1+1+1+1
    5=1+1+1+2
    5=1+2+2
    5=1+4
    5=2+3

    注意,本题中N拆分出来的数x的范围是1<=x<N。假如x可以等于N,那么本题和整数划分是一个道理。现在,这里与整数划分这个题的答案只少1,即N拆分成N本身的情况。

    整数划分可以参考:

    http://www.cnblogs.com/hoodlum1980/archive/2008/10/11/1308493.html

    http://blog.csdn.net/sunquana/article/details/9245443

    算法一  用回溯法来实现

    针对所给问题,定义问题的解空间;如本题对5的拆分来说,1<=拆分的数<5

    确定用于搜索的解空间结构;如本题对5的拆分来说,x[ ]数组来存储解,每个数组元素的取值范围都是1<=拆分的数<=5,从1开始搜索直到5 

    搜索解空间,并在搜索过程中用剪枝函数避免无效搜索。

    如本题对5的拆分来说,为了避免重复,x[i] >= x[j]  ( i > j ),如x[]={2,3}满足条件而x[]={3,2}就不满足条件不是可行解即无效

     1 #include<stdio.h>
     2 #include<stdlib.h>
     3 
     4 void splitN(int n,int m);// n是需要拆分的数,m是拆分的进度。
     5 int x[1024]={0},total=0 ;// total用于计数拆分的方法数,x[]用于存储解
     6 void main()
     7 {
     8     int n ;
     9     printf("please input the natural number n:");
    10     scanf("%d",&n);
    11     splitN(n,1);
    12     printf("There are %d ways to split natural number %d. ",total,n);
    13 }
    14 
    15 void splitN(int n,int m)
    16 {//n是需要拆分的数,m是拆分的进度
    17     int rest,i,j;
    18     for(i=1;i<=n;i++)
    19     {//从1开始尝试拆分
    20         if(i>=x[m-1])
    21         {//拆分的数大于或等于前一个从而保证不重复
    22             x[m]=i ;// 将这个数计入结果中
    23             rest=n-i ;// 剩下的数是n-i,如果已经没有剩下的了,并且进度(总的拆分个数)大于1,说明已经得到一个结果了
    24             if(rest==0&&m>1)
    25             {
    26                 total++;
    27                 printf("%d	",total);
    28                 for(j=1;j<m;j++)
    29                 {
    30                     printf("%d+",x[j]);
    31                 }
    32                 printf("%d ",x[m]);
    33                 printf("
    ");
    34             }
    35             else
    36             {
    37                 splitN(rest,m+1);// 否则将剩下的数进行进度为m+1拆分
    38             }
    39             x[m]=0;// 取消本次结果,进行下一次拆分。环境恢复,即回溯
    40         }
    41     }
    42 }
    View Code

    算法二  用递归来实现

    用不完全归纳法
    n =2 可拆分成 2 =1 +1
    n =3 可拆分成 3 =1 +2 =1 +1 +1
    n =4 可拆分成 4 =1 +3 =1 +1 +2 =1 +1 +1 +1 =2 +2
    ……
    n =7 可拆分成 7=1 +6
    =1 +1 +5
    =1 +1 +1 +4
    =1 +1 +1 +1 +3
    =1 +1 +1 +1 +1 +2
    =1 +1 +1 +1 +1
    =1 +1 +1 +2 +2
    =1 +1 +2 +3
    =1 +2 +4
    =1 +2 +2 +2
    =1 +3 +3

    =2 +5
    =2 +2 +3

    =3 +4

    用数组 a 存储完成 n 的一种拆分。从上面不完全归纳法的分析 n =7 时,
    按 a[1]分类,有a[1]=1,a[1]= 2,…,a[1]= n/2,共 n/2 大类拆分。
    在每一类拆分时,a[1]= i ,a[2]= n - i ,从 k=2,从 a[k]开始继续拆分,
    a[k]能否再拆分取决于 a[k]/2 是否大于等于 a[k-1]。
    递归过程的参数 t 指向要拆分的数 a[k]

     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 
     4 int a[100]={0};
     5 void Split(int t)
     6 {
     7     int i,j,L;
     8     for(i = 1; i <t; i++)
     9     {
    10         printf("%d+",a[i]);
    11     }
    12     printf("%d
    ",a[i]);
    13 
    14     j = t;
    15     L = a[j];
    16     for(i = a[j-1]; i <= L/2; i++)
    17     {
    18         a[j] = i;
    19         a[j+1] = L - i;
    20         Split(j+1);
    21     }
    22 }
    23 
    24 void SplitNum(int n)
    25 {
    26     int i;
    27     for(i = 1; i <= n/2; i++)
    28     {
    29         a[1] = i;
    30         a[2] = n - i;
    31         Split(2);
    32     }
    33 }
    34 int main()
    35 {
    36     int n;
    37     scanf("%d",&n);
    38     SplitNum(n);
    39     return 0;
    40 }
    View Code

    参考:http://wenku.baidu.com/link?url=H7tDqvEmnds9SN4FfuwMw8M6AfAMUl44-vCR83Z4LKv9UN-HAU159GJtFR5M48t11XBJFMwP3i4qPk6u2WHEORZDeYhraBQt63zvaDUNSAi

  • 相关阅读:
    js与asp.net后台交互
    Asp.net封装js的类
    RegisterClientScriptBlock 与 RegisterStartupScript 的区别
    Page.ClientScript.RegisterStartupScript()
    错误与修复:ASP.NET无法检测IE10,导致_doPostBack未定义JavaScript错误,恒处于FF5卷动条位置
    JS数组的操作
    拉里·埃里森和历史上最牛的演讲【转】
    SSIS 学习(9):包部署常见问题汇总【转】
    SSIS 学习(8):事务【转】
    SSIS 学习(7):包配置(下)【转】
  • 原文地址:https://www.cnblogs.com/huashanqingzhu/p/4748652.html
Copyright © 2020-2023  润新知