前言
之前将近一个星期都在忙CATIA去了,优快云被搁在一边,当时写好的都忘了发。今天回到对学校逆天题目的分享上
题目
有问题的思路历程
注:以下内容处于我个人的想法,一定程度上受对编程里二进制运算知识应用欠缺的影响。可以跳过
写一个函数能输出n的二进制对应位数
代码如下
#include<stdio.h>
#include<math.h>
int sec1(int n){
int i = 0;
while(pow(2,i)<=n)
i++;
i--;
return i;
}
void sec(int arr[],int n){
int i = 0;
while(pow(2,i)<=n)
i++;
//printf("%d\n",i);
i--;
int t=0;
while(n>0){
if(n-pow(2,i)>0){
arr[t]=i;
t++;
n-=pow(2,i);
}
i--;
}
}
int main() {
int arr[100];
int n=0,j=0;
scanf("%d",&n);
int m = n;
sec(arr,m);
while(j<=sec1(n)&&arr[j]>=0){
printf("%d ",arr[j]);
j++;
}
return 0;
}
结果:
虽然看起来距离正确答案有点接近了,但是这样写存在很大的潜在问题:首先是对于奇数,2
的零次方是不会在输出中有体现的;其次,二进制表示的过程存在多次迭代,会使main函数里的调用杂乱不堪。
推荐采用递归函数来解决问题
答案
老师的解法
#include<stdio.h>
#include<math.h>
void putqupoly(int t)
{ int i = 8*sizeof(int), b ,flag = 0;
for(b=1<<(i-1);i>=0; )
{ t<<=1;
i--;
if(t&b)
{
if (flag)
printf("+");
if (i>=3)
{
printf("2(");
putqupoly(i-1);
printf(")");
}
else if (i==2)
printf("2");
else if (i==1)
printf("2(0)");
flag=1;
}
}
}
int main()
{
int n;
scanf("%d",&n);
putqupoly(n);
return 0;
}
老师的解法与我一开始想的不同,是将输入数从二进制高位开始一个一个往下算,即123=2^6+ 25+24+23+21+2^0,则将6一步算到底,输出2(2(2)+2)之后再对下一位5进行转换。
同时,由于题目中对n的范围有所界定,为1到10000之间的数,则n其实已经被涵盖在所有int型数据之中,而int型在储存时最多能储存32/64位二进制数(根据计算机配置而定,因此采用8*sizeof(int)
的保守写法)
b=1<<(i-1)
将b左移至最高位,即此时b的二进制表示为100000……共30个0。
注:
(1)因为int型第一位为符号位,故正数b与t的第一位一定是相等的,因此在迭代时直接从第二位开始;
(2)此处1<<(i-1)
表示将1的二进制位左移,而不是将二进制的1左移,因此相当于把二进制第零位上的1左移(i-1)位;
接着进入for循环:
t<<=1;
将t左移一位。(为啥放在for循环开头其实我也不太理解,个人推测可能是因为不论是32bit还是64bit,首位的二进制表示值都远远大于10000,所以放在前面影响不大。望大佬指正)
这一步就像一个断头台,而后面if(t&b)
则是一把铡刀,将t的二进制高位一个一个截取。
记得在进入if语句前执行i--;
,一是因为需要用i来判断t的左移次数,进而判断是否可以出循环;二是因为
if (flag) printf("+");
只是为了满足题目输出要求而设,每经历一次循环,flag便会被赋1,以便下一次循环时先打“+”号。
当i>=3时,进入第二个if语句,其中
printf("2(");
和printf(")");
是用来打印结果中的首尾部分;
putqupoly(i-1);
是对其对应位数的再次二进制化,为什么要用i-1呢,我们可以举个例子看看:
例如:当t=7时,t的二进制为00……00000111(共32-3=29个0),在i–至i=3后,进入if语句,执行 putqupoly(3-1);
,最终输出2(2)
看出以上内容错在哪里了吗,
留意注:(1)
因为b是0100……00(32-2=30个0),而从for循环中可以看出,t每左移一位,i才–。因此,t左移至第2位时,需左移29-1=28次,而i也因此–了28次,i=32-28=4.所以在i=4时便可以进入if语句 putqupoly(4-1);
最终输出2(2+2(0)) 。
以上就是所有关于老师提供的解法的分享。可以说是main函数最没面子的一集。
不过老师的解法给了我一点灵感,既然题目变态,那我也玩
抽象
int main() {
int arr[100];
int n=0,j=0;
scanf("%d",&n);
int m = n;
sec(arr,m);
while(j<=sec1(n)&&arr[j]>=0){
switch (arr[j]){
case 14:printf("2(2(3)+2(2)+2)+");break;
case 13:printf("2(2(3)+2(2)+2(0))+");break;
case 12:printf("2(2(3)+2(2))+");break;
case 11:printf("2(2(3)+2+2(0))+");break;
case 10:printf("2(2(3)+2)+");break;
case 9:printf("2(2(3)+2(0))+");break;
case 8:printf("2(2(3))+");break;
case 7:printf("2(2(2)+2+2(0))+");break;
case 6:printf("2(2(2)+2)+");break;
case 5:printf("2(2(2)+2(0))+");break;
case 4:printf("2(2(2))+");break;
case 3:printf("2+2(2(0))+");break;
case 2:printf("2+");break;
case 1:printf("2(0)+");break;
}
//printf("%d ",arr[j]);
j++;
}
printf("\b ");
return 0;
}
不做解释!!!遥遥领先
总结
最近比较忙,可能做不到日更,抱歉