整数分划问题

一、问题描述

  整数分划问题:对于一个正整数n的分划就是把n写成一系列正整数之和的表达式。要求给出分划方式与分划数目的总和

二、问题分析

  这个问题用暴力搜索、循环、递归都能解决,但用递归是最灵活的,本题采用递归的方式求解。以n=5为例,手动列出正整数之和的表达式,可以发现以下规律:
5          …各正整数不大于5
4+1         …各正整数不大于4
3+2 ,3+1+1     …各正整数不大于3
2+2+1 ,2+1+1+1   …各正整数不大于2
1+1+1+1+1      …各正整数不大于1
  自顶向下分析,第m层的正整数都是不大于m的(例如,第3层的“3+2 ,3+1+1”都不大于3),由此我们可以得到一个除了n以外的新变量:m。
  由此,求各数不大于5的划分=包含5的划分+不包含5的划分(包含小于等于4的划分);各数不大于4的划分=包含4的划分+不包含4的划分(包含小于等于3的划分)。这样自顶向下分析下去,终点是“各数不大于1的划分,即m=1”,除此之外,再观察输入,会发现还有一个终止条件是“n=1”。
  总结,求正整数5的分划就是求“不大于5的正整数的组合成5”的问题,用一个带参数的函数来表示就是Fenhua(n,m)。

三、算法设计

  其中包含的递归关系有:
①Fenhua(n,n)=1+Fenhua(n,n-1),这是观察得出的,算是一种特殊情况,也就是最顶层的只有一种划分。
②Fenhua(n,m)=Fenhua(n,m-1)+Fenhua(n-m,MIN(m,n-m)),这是一条普遍规律,也就是划分成了正整数包含m和不包含m两种情况。
Fenhua(n,m-1)的语义是:n不包括m的分划数目
Fenhua(n-m,MIN(m,n-m))的语义是:n包括m的分划数目
  该递归的终止条件是:
①n=1
②m=1
  好了,掌握了以上的两种关系、两种终止条件,就能设计出算法了,大功告成!

#include<stdio.h>

int Fenhua(int n,int m);
int main()
{
   	int n=5,m=5;
   	int a=Fenhua(n,m);
   	printf("%d",a);
}
   
     int Fenhua(int n,int m)
   {
   	if(n<1|| m<1 || m>n)
   	    printf("输入错误");
   	else if(n==1||m==1)
   	//被划分数是1,只有一个划分;构成数不大于1,只有一种划分 
   	    return 1;
   	else if(n==m)
   	//n构成n自己这一种划分 
   	  return(1+Fenhua(n,n-1)); 
   	else {
   		//下面的if比较是为了,让函数的第一个参数大于等于第二个参数 
   		int t;
   		if(n-m<m)
   		  t=n-m;
   		else
   		  t=m;
   		return(Fenhua(n,m-1)+Fenhua(n-m,t)) ;
	   }
	   
   }

  但是呢,好像没太懂为啥要这样递归勒。
在这里插入图片描述
   大多数人不明白的地方是Fenhua(n-m,MIN(m,n-m)),这里会产生两个问题:

(一)为什么第一个参数是n-m
(二)为什么第二个参数m和n-m要取最小值。

  (一)首先是第一个问题:Fenhua(n-m,MIN(m,n-m))的语义是“n包括m的分划数目”,既然n中已经包括m了,那么我们就知道n的组成数中已经有一个是m了,所以接下来求n-m的组成数就好了。比如我们要求“5包含3的分划数目”,只需要求5-3=2的分划数目就好了:
                        3+2 ,3+1+1
  (二)然后回答第二个问题,还是要看一下Fenhua(n-m,MIN(m,n-m))的语义“n包括m的分划数目”,但是我们在上一问已经将这个问题转化过了,语义变为“n-m的所有分划数目”,会出现两种情况:(1)n-m<m (2)n-m>m。
(1)简单说就是n减去m以后这个数可能比m要小了,此时m无法构成n-m了,就要让n-m替代m的位置,此时应该是Fenhua(n-m,n-m)。
(2)n减去m以后这个数大于等于m,此时应该是Fenhua(n-m,m)。
  综合(1)(2)来看,Fenhua的第二个参数取的是最小值。

一年以后再来写这个代码,就没有那么拖沓了

#include<bits/stdc++.h>
using namespace std;
/*
代码使用:改main函数里的初始值(6,6),然后直接编译运行 
*/
int Fenhua(int n,int m){
	if(n==1||m==1){
		return 1;
	}else if(n==m){
		return 1+Fenhua(n,n-1);
	}else{
		return Fenhua(n,m-1)+Fenhua(n-m,min(n-m,m));
	}
}

int main(){
	int result=0;
	result=Fenhua(6,6);
	cout<<result;
	return 0;
}

  • 9
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值