uva 11121 Base -2
数学题,给定一个十进制数转化为-2进制。这个问题可以扩展为转化为任意的负进制,先说-2进制
算法:n mod -2 余数可能为-1,0,1,但是不能出现-1,只能有0,1所以将-1变为1,并且商要加1。然后依此迭代直到商为0为止。
为什么余数要变为1而且能变为1呢,变了之后要怎么做呢?我找了很多博客都没有说原理,只是简单一句话,可能大家都觉得很简单吧,但是我还是想了一段时间才想出来的,所以就写一下原理
我们来看一个10进制转2进制,例子1024
第0次迭代,1024/2=512,1024%2=0 , 试一下把512++变为513,那么逆回去就是1026,多了2,其实就是2^1
第1次迭代,512/2=256,512%2=0,试一下把256++变为257,那么逆回去,就是1028,多了4,其实就是2^2
说到这里应该很清晰了,在第i次迭代后商+1,其实相当于原来的数增加了2^(i+1),这个有什么用呢
n = b0 + b1(-2) + b2(-2)2 + b3(-2)3 + ...
当n为正数的时候,第i次迭代的时候余数为-1的话,那么i一定是奇数(因为余数为正为负只和n的正负有关,而n的正负在除-2的过程中是交替变化的,很容易可以知道当i为奇数的时候,n是负数或0,余数是-1或0)那么对应的位置就应该是 -1*(-2)^i=2^i ,如果变为1,则是1*(-2)^i=-2^i ,所以变为1后相当于减少了2*2^i=2^(i+1),减少了的要加回来啊,怎么加,就在第i次迭代后的商+1,上面说了,第i次迭代后商+1,相当于逆回去加了2^(i+1),所以以这个商继续迭代下去,最后得到的-2进制数就会等于原来的n
同理,当n为负数的时候,也是一样的分析,就不写了。
然后看代码
#include <cstdio> #include <cstring> #define N 110 int a[N]; int n; int main() { int t,T; scanf("%d",&T); for(int t=1; t<=T; t++) { scanf("%d",&n); int c=-1; a[0]=0; while(n) { a[++c]=n%(-2); n=n/(-2); if(a[c]==-1) { a[c]=1; n++; } } printf("Case #%d: ",t); while(c>0) printf("%d",a[c--]); printf("%d",a[0]); printf("\n"); } return 0; }
按照这个原理我们不难写出转化为任意负进制的代码,先简单文字描述
当n为正数的时候转化为-m进制,同样是当i为奇数的时候,会产生负的余数(或者0)-p,对应的位为(-p)*(-m)^i=p*m^i , 要把-p改为m-p , 那么对应的为就变为了(m-p)*(-m)^i=-(m-p)*m^i , 那么相当于原来减少了m*m^i=m^(i+1) , 减少的要补回来,就是在商那里+1,那么逆回去相当于增加了m^(i+1),刚好不回来,那么转化后的-m进制才是n
同理n为负数的时候也是这么分析的
核心代码
//核心代码 scanf("%d",&n); int c=-1; a[0]=0; while(n) { a[++c]=n%(-m); //m就是m进制,-m就是负进制 n=n/(-m); if(a[c]<0) { a[c]=m+a[c]; n++; } } printf("Case #%d: ",t); while(c>0) printf("%d",a[c--]); printf("%d",a[0]); printf("\n");