第二章主要讲的是循环结构部分。学到的东西如下:
1、7744问题(输出形如aabb的完全平方数)
代码1:(sqrt取aabb平方根,将其转化为int型m,判断m*m是否和原数相等)
int main()
{
for(int i=1;i<10;i++)
{
for(int j=0;j<10;j++)
{
int aabb=i*1000+i*100+j*10+j;
int m = floor(sqrt(aabb) + 0.5);//为减小误差,采用四舍五入
if(m*m==aabb)
printf("%d\n",aabb);
}
}
return 0;
}
floor()函数用于返回不大于x的最大整数。
int强制类型转换和floor()的区别:
int是向0取整,如1.8会变成1,-1.8会变成-1;
floor是向下取整,如1.8会变成1,-1.8会变成-2;区别就在于这里。还有一个区别是类型,int强制类型转换转换后是int型,而floor返回的是浮点型。
顺便扩展了一下,由于整数的表示范围远小于浮点数的表示范围,直接采用强制转换把浮点数转换成整数有可能出现数据错误,所以建议使用floor()函数实现”不大于X的最大整数“,完成对X的取整操作,如果想实现“向上取整”,则floor()之后再加1,表示方法为:floor(x)+1,输出方法为:%.0f不输出小数部分。
如果想实现“四舍五入”,则使用floor(x+0.5)。可以想象成在数轴上把一个单位区间往左移动0.5个单位的距离。floor(x)等于1的区间为[1,2),而floor(x+0.5)等于1的区间为[0.5,1.5)。
代码2:(我自己的做法,循环判断找出满足条件的)
int main()
{
for(int i=1;i<10;i++)
{
for(int j=0;j<10;j++)
{
int aabb=i*1000+i*100+j*10+j;
for(int m=0;m*m<9999;m++)
{
if(m*m==aabb)
{
printf("%d\n",aabb);
break;
}
}
}
}
return 0;
}
代码3:(枚举平方根,避免开平方的操作。书上的这个操作是x一直增大,寻找出x*x的值在1000到9999之间的数,再判断其前两位和后两位是否相等,也是个很清奇的思路啊)
int main()
{
for(int x;;x++)
{
int n=x*x;
if(n<1000)
continue;
if(n>9999)
break;
if((n/1000==n/100%10)&&(n%10==n%100/10))
printf("%d\n",n);
}
return 0;
}
学到一点,continue是指跳回for循环的开始,执行调整语句并判断循环条件(即“直接进行下一次循环”),break是指直接跳出循环。以前一直以为continue即使继续,啥也不干,没有理解到这个层次。
2、3n+1问题
我的初始代码(看似没有问题,实际上是错误的没有考虑到n值太大,溢出问题)
int main()
{
int n;
scanf("%d",&n);
int count=0;
while(n!=1)
{
if(n%2==0)
n=n/2;
else
n=n*3+1;
count++;
}
printf("%d\n",count);
return 0;
}
解决方案为改成long long类型(其范围是-2的64次方~2的64次方-1)
在当前流行的竞赛平台中,int都是32位整数,范围是-2147483648~2147483647,即-2的31次方~2的31次方-1。(以前以为int都是大于等于0的整数,把int和unsigned int搞混了,unsigned int是大于等于0的,范围是0~2的64次方-1)
本题中n的上限10的9次方只比int的上界稍微小一点,因此溢出了。哇,之前天真的以为只要比2的31次方-1小,哪怕一点点都是可以用int的,大错特错了,稍微小一点点溢出就变成了很正常的事情。
体会到了温故而知新,今晚就到这吧,over~