题目描述:
我们要求找出具有下列性质数的个数(包含输入的自然数nnn):
先输入一个自然数nnn(n≤1000n \le 1000n≤1000),然后对此自然数按照如下方法进行处理:
1.不作任何处理;
2.在它的左边加上一个自然数,但该自然数不能超过原数的一半;
3.加上数后,继续按此规则进行处理,直到不能再加自然数为止.
输入格式:
1个自然数n
输出格式:1个整数,表示具有该性质数的个数;
输入样例
6
输出样例
6
乍一看这道题有点难度,但是仔细思考过后就会有新的发现。根据数学推导的方式进行分析,可以得到一个递推公式,那就是,a[n]=a[1]+a[2]+…+a[n/2]+1;
此处的n是咱们一开始所输入的数字,那么为什么会得出上面那个公式呢?
这应该是很多人所疑惑的地方,接下来我将仔细地对其进行讲解。
推到思路:
1.首先咱们需要明确一点,咱们所输入的数字前面添加的第一个数字一定会小于等于这个数字的一半(也就是如果我输入了6,那么前面一位可以添加1,2,3三个数字,因为这三个数字都符合小于等于所输入数字一半的要求。
2.这也是思考的拐点,当我确认我所输入的数字的前一位数之后,我就可以不去管我所输入的数字了(也就是说,当我计算出1,2,3符合条件后我就可以不去看他们的后一位也就是我之前所输入的数字6,因为接下来的所有计算过程都将依赖于我所计算出来的新的数字。
举例说明:
我用数字6计算出,1,2,3三个数字之后我选定一种情况进行参考,假定我选择了3,我依靠数字3计算出3前面的数字是1,根据题目的要求,我可以得出当我选定6的前位数为3的时候有两种情况,36,136,其实你应该注意到了,当你在计算这种情况的时候,就会发现,此时这两种情况的来源正是这道题目输入值为3的输出值,这不是巧合,当选定数字为2和1的时候依然可以得到这个结论,据此我们得到了一种特殊情况的递推式a[6]=a[1]+a[2]+a[6/2]+1;(加上一个1是为了题目所要求的第一条要求。
3.那么最后我们将上述的结论拓展到n,那么就得到了咱们所需要的公式:a[n]=a[1]+a[2]+…+a[n/2];如果你足够细心的话会发现,当n为奇数的时候n/2和(n-1)/2相同所以可以不做特殊考虑
#include<stdio.h>
void count(int n,int a[])
{
int i,j;
for(i=2;i<=n;i++)
{
for(j=1;j<=i/2;j++)//这一步不用多说了就是上述公式的“代码表达式”
{
a[i]=a[i]+a[j];
}
a[i]++;//可别忘了加1
}
}
int main()
{
int n;
int a[1100]={1,1};//我要创建一个数组来储存所有遍历到的数字的输出结果,
//第0位和第1位都初始化为1,根据题目要求
scanf("%d",&n);//输入数值
count(n,a);//这是一个递推过程函数,用来计算数组里面的数值。
printf("%d",a[n]);//输出结果
return 0;
}
其实写完之后总感觉自己怪罗嗦的,你能看到这儿已经很棒了呢!希望这篇博客能成为你coding之路上的一次助力,期待与你的再次相逢。