如果n为偶数,则将它除以2,
如果n为奇数,则将它加1或者减1。
问对于一个给定的n,怎样才能用最少的步骤将它变到1。
例如:
n= 61
n-- 60
n/2 30
n/2 15
n++ 16
n/2 8
n/2 4
n/2 2
n/2 1
2,算法
输入:一个32bit无符号数in.
输出:经过DIV/ADD/SUB变为1的步骤.
注:
DIV--- /2操作;
ADD--- ++操作;
SUB--- --操作;
1),if (in==1)
转3);
else
转2);
2),if(in is even)
in = in DIV 2;
print div 操作;
else
令 res1 = in-1 中所包含的bit 1的个数;
令 res2 = in+1 中所包含的bit 1的个数;
if (res1<=res2)
in = in SUB 1;
print SUB 操作;
else
in = in ADD 1;
print ADD 操作;
endif
转1);
3),退出
3,证明
1),DIV/ADD/SUB三种运算,DIV是使in最快逼近1的运算;
2),使用DIV需要满足(in&1) == 0的条件,如果不能满足该条件,
只能使用ADD/SUB运算;
3),in包含的bit 1越多,就需要更多的ADD/SUB步骤;
在选择使用ADD/SUB运算过程中,将计算结果包含bit 1的
个数最少作为选择的标准,使得所选择的运算是当前步骤中
最优的.
附:算法的c源码(在linux下调试通过)
#include
#include
#include
/*
compute the number of the bit 1 in the para bits
*/
static unsigned int get_one_number(unsigned long bits)
{
unsigned int ret = 1;
while(bits &(bits-1))
{
ret++;
bits = bits & (bits-1);
}
return ret;
}
int main(int argc,const char* argv[])
{
unsigned long in = 0;
unsigned int out = 0;
in = strtoul(argv[1],NULL,10);
// out = get_one_number(in);
// printf("0x%8x have %4d bit1/n",in,out);
while(in!=1)
{
if (in&1UL)
{
unsigned long res1,res2;
res1 = get_one_number(in-1);
res2 = get_one_number(in+1);
if (res1<=res2)
{
printf("%8d(%8x) %8d(%8x) step=%s/n",in,in,in-1,in-1,"SUB");
in-=1;
}
else
{
printf("%8d(%8x) %8d(%8x) step=%s/n",in,in,in+1,in+1,"ADD");
in+=1;
}
}
else
{
printf("%8d(%8x) %8d(%8x) step=%s/n",in,in,in>>1,in>>1,"DIV");
in>>=1;
}
}
return 0;
}