一、题目
N人围成一个环,每个人一个编号1—n,然后1、2报数,报2出局,其余人继续,直至最后一人。求该人的编号。有时间限制
二、分析
找规律: 我直接写出了n从1—17的最终答案,分别为:1、1、3、1、3、5、7、1、3、5、7、9、11、13、15、1…发现其是以2的幂次方为一个轮回,然后奇数增长。
分开更容易看清:
第一轮:1
第二轮:1、3
第三轮:1、3、5、7
第四轮:1、3、5、7、9、11、13、15
…
个数刚好为1、2、4、8…
编写代码思路:首先我们要确定所给的数n是经历了几轮这样的循环,然后再确定是这一轮的哪个位置即可算出结果。
这里我们设为x轮,则有
这里c为一个变量。我们把所给数n放在第x+1轮,其前面总有x轮(x>=0)。
①求x:
因为有2^x-1+c=n,两边取对数:x=log2(n)-log2(c-1);
由于为整数,所以x=log2(n)向下取整即可(代码中已经自动实现向下取整,故不必考虑)。
c语言编程实现,可以使用log()函数。不过log()函数以10为底的,我们可以利用对数函数的换底公式。
于是则有:log2(n)=log10(n)除以log10(2)。
代码实现为: x = log(n)/log(2);
在求出经历x轮后,还得求出是第x+1轮的哪个位置。这里设为num,
②求num:
因为有2^x+num=n,故num=n-2 ^x。
③算出结果y
根据1,3,5,7……这样的规律
y=2*num+1。
三、算法实现
int main()
{
long long n,x,y,num;
while(scanf("%lld",&n)!=EOF)
{
x = log(n)/log(2);//计算出经历的轮数。
num=n-pow(2,x);//所在的轮数的第num位上
y=2*num+1;//求最终值。
printf("%lld\n",y);
}
return 0;
}
四、算法分析
此算法为公式计算,故可以得出其时间复杂度为O(1).根据程序,易知空间复杂度为O(1)。 感受数学在编程过程中的无比魅力,数学思维很重要