的士数
01:首先是要理解的士数的概念:定义第n个的士数,就有n种方法的 两个数的三次幂 的和等于这个数字,比如说第一个的士数是:
1 = 111 + 111
第二个的士数:
1729 = 111 + 121212
= 999 + 101010
第三个的士数:
87539319 = 167167167+ 436439439
= 228228228+ 423423423
= 255255255 + 414414414
。。。。。。。
暴力循环
通过输入的数字设置循环的范围,然后就是直接设置两重循环
通过一个个数字的三次幂相加的结果是不是和原来的数字相等来判断,是的话用一个变量key来记录下次数,第一次的时候,找到一次的话就是的士数,把它输出,然后设置一个变量flag,让flag等于 key + 1, 继续下次的循环,每一次输出也就是你找到了一个的士数的时候就自加一,也就是这样去找下一个的士数,通过flag操作,(为的是保持key的值一直是这一次要找的第几个的士数的标志,这样的话就是要找到 key次相等的情况,这样再输出,也就是说可以设置flag每次找到一次合适的数字的三次幂的和等于原来的数字的时候减去一个一,(这里要注意循环的时候,两个数字可以交换位置,会找到两次相等的情况,但是实际上只是一种方法,所以当两个数子相同和不同的情况下也是要分开的), 并且每次的情况一定要是同一个数字的,之前我犯了这个错误,没有注意到这一点,导致,输出第二个的士数的时候出现错误。第一个数字是1,key加上一是2,赋值给flag,当算到数字9的时候,1,2是符合情况,然后设置的flag本来是2现在减去了一个1等于1,预想是再找到两个数字三次幂的和等于9的时候,那它就是第二的士数,但是找不到了,也就是说她不是的士数,但是因为这时候循环跳出去之后继续下去,flag的数字应该变回原来的2,但是没有,所以下一次找到16的时候, 2,2的三次幂之和为16,导致flag-1为0了,导致输出这个数,实际上是要再找两个数字才能输出的,但是前面没有复原flag的值导致了错误。
—————————————————————————
代码:
/*
从键盘输入一个数字,找出所有小于
这个数字的所有的士数
*/
#include<stdio.h>
int main()
{
int num;
float key = 1.0; // 用来记录是第几个的士数
float flag; // 控制判断的士数
scanf("%d",&num);
int time = 1;
for(int i =2; i<num;i++)
{ flag = key;
for(int j = 1; j<i; j++)
{
for( int n = 1; n< i; n++) // 2.0 16
{
if(i == j*j*j + n*n*n) //两个数字相同这样的话,程序只会记一次
{ //printf("hello");,这里是执行的
if(n == j)
{
flag = flag - 1.0; // 控制变成零之后输出 9
//printf(" %f ",flag);
}
//printf(" %f ", flag);
else // 没有设置是同一个数再相减
{ // 导致9的时候flag减了1,之后16的时候就可以输出了
flag = flag - 0.5;
//printf(" _%d_%d_ ", j,n);
}
//printf(" %f ", flag);
}
if(flag == 0 )
{
if(time == 1)
{
printf("%d", i); // 输出的士数
time = time + 1;
//printf(" _%d_%d_ ", flag);
}
else
{
printf(",%d", i); // 为了控制输出格式
}
key = key +1.0;
flag = key; // 满足找到key次之后才是的士数
//printf(" %f ", flag);
}
}
}
}
return 0;
}
改进
这样的循环实在是太长了,优化一下,从循环节的控制上面下手,也就是找到的两个数字其中一个数字的三次方大于原数的话都不会成立,那就从这里下手,控制循环是在1到 pow(i,1.0/3),这样的话可行。改一下就好了。
—————————————————————————