After read Dr. D.E.Knuth's book, Mr. Bpt finds an interesting thing.
As we all known, a decimal number may be represented in binary form. For example, we are able to use (101)2 represent (5)10. And decimal number set {0, 1, 2, 3} can be changed to {00, 01, 10, 11} in binary. If we put them into a certain order, we can get a sequence like 00,01,11,10. And in this sequence, each two adjacent numbers have one and only one different digit (we can assume there are some zeros in the front of each number so that all of them have the same length) including the first number 00 and the last number 10.
Now Mr. Bpt has confirmed that to any non-negative integer N, there are such sequences formed by integer 0, 1, ... , 2N-1 as described above. Mr. Bpt wants you to help him to find the "smallest" sequence. "Smallest" means the first number in this sequence should not be bigger than the first number in other sequences. If there are some sequences having same first number, you should compare the second number and so on until you find the unique sequence.
Input
Input only contain one integer N as mentioned above (0<= N <= 18).
(Please use standard input, and don’t read or write files.)
Output
Output contains 2N line, every line contains one number, and put them in decimal, which represents the sequence Mr. Bpt wants.
(Please use standard output, and don’t read or write files.)
Sample Input
2
Sample Output
0
1
3
2
Source
'Crazy for Programming'Nankai University Programming Contest V
==================================================================
这个题目刚开始想了很久,后来想起了数字逻辑的卡诺图。
虽然卡诺图能够很方便地找到相邻两个只变一位的二进制数,但是其多维的复杂度很可怕,而且经常会有走入死胡同的危险。然而,现在我们遇到的这个问题可能并不适合用卡诺图解决。
后来,随便把杨老师的教材看了看,发现了格雷码(Gray Code)。而这个问题,有点类似Gray Code,只是这个问题是有序。
趁这个机会,把可靠性编码之一——Gray Code复习一下:
=====================================================
在数字系统中只能识别0和1,各种数据要转换为二进制代码才能进行处理,格雷码是一种无权码,采用绝对编码方式,典型格雷码是一种具有反射特性和循环特性的单步自补码,它的循环、单步特性消除了随机取数时出现重大误差的可能,它的反射、自补特性使得求反非常方便。格雷码属于可靠性编码,是一种错误最小化的编码方式,因为,自然二进制码可以直接由数/模转换器转换成模拟信号,但某些情况,例如从十进制的3转换成4时二进制码的每一位都要变,使数字电路产生很大的尖峰电流脉冲。而格雷码则没有这一缺点,它是一种数字排序系统,其中的所有相邻整数在它们的数字表示中只有一个数字不同。它在任意两个相邻的数之间转换时,只有一个数位发生变化。它大大地减少了由一个状态到下一个状态时逻辑的混淆。另外由于最大数与最小数之间也仅一个数不同,故通常又叫雷反射码或循环码。
Algorithm Gossip: 格雷碼(Gray Code)
說明
Gray Code是一個數列集合,每個數使用二進位來表示,假設使用n位元來表示每個數好了,任兩個數之間只有一個位元值不同,例如以下為3位元的Gray Code:
000 001 011 010 110 111 101 100
由定義可以知道,Gray Code的順序並不是唯一的,例如將上面的數列反過來寫,也是一組Gray Code:
100 101 111 110 010 011 001 000
Gray Code是由貝爾實驗室的Frank Gray在1940年代提出的,用來在使用PCM(Pusle Code Modulation)方法傳送訊號時避免出錯,並於1953年三月十七日取得美國專利。
解法
由於Gray Code相鄰兩數之間只改變一個位元,所以可觀 察Gray Code從1變0或從0變1時的位置,假設有4位元的Gray Code如下:
0000 0001 0011 0010 0110 0111 0101 0100
1100 1101 1111 1110 1010 1011 1001 1000
觀察奇數項的變化時,我們發現無論它是第幾個Gray Code,永遠只改變最右邊的位元,如果是1就改為0,如果是0就改為1。
觀察偶數項的變化時,我們發現所改變的位元,是由右邊算來第一個1的左邊位元。
以上兩個變化規則是固定的,無論位元數為何;所以只要判斷位元的位置是奇數還是偶數,就可以決定要改變哪一個位元的值,為了程式撰寫方便,將陣列索引 0當作最右邊的值,而在列印結果時,是由索引數字大的開始反向列印。
將2位元的Gray Code當作平面座標來看,可以構成一個四邊形,您可以發現從任一頂點出發,繞四邊形周長繞一圈,所經過的頂點座標就是一組Gray Code,所以您可以得到四組Gray Code。
同樣的將3位元的Gray Code當作平面座標來看的話,可以構成一個正立方體,如果您可以從任一頂點出發,將所有的邊長走過,並不重複經過頂點的話,所經過的頂點座標順序之組合也就是一組Gray Code。
實作
· C
· Java
·
老古论坛:
(1)格雷碼為無權值碼,不適合做運算。
(2)是一種最小變化碼,其最主要特性是任意相鄰兩數,只有一個Bit改變,因此,適合做資
料傳輸、類比/數位轉換、輸出入裝置等。
(3)具有上下反射性,所以又稱為反射數碼
(4)二進碼轉換成格雷碼:
1.二進碼之MSB即為格雷碼之MSB。
2.二進碼之MSB起,兩兩Bit做互斥運算,即是相對應之格雷碼。
例 : 求27(D)之格雷碼
解: 27(D) = 1 1 0 1 1 B
1 1 0 1 1 B
方法:先将低俩位进行异或,11异或得0,再01异或得1,再10异或得1,再11异或得0,然后
高位照写,结果为:10110(GRAY)。
(5)格雷碼轉換成二進碼:
1.格雷碼之MSB,即為二進碼的MSB。
2.二進碼的MSB與格雷碼的次高Bit做互斥運算,其結果即是二進碼的次高Bit,以
此方式進行運算即可。
例 2: 將 1 1 0 1 0 1 (Gray)轉換成二進碼
解: 110101(G)=100110(B)
你的格雷码:203(G)=1100000010(G)转换为二进制为:10 0000 0011(B)
我的将二进制转化成Gray Code的代码:
问题:
虽然Gray Code和这个题目看似相关,n=2时答案也正确,但是毕竟还是有些不同。有高手吗,支招?
public class GrayCode {
private char[] digit;
private boolean first;
private boolean odd;
private int count;
public GrayCode(int length) {
digit = new char[length];
for(int i = 0; i < length; i++) {
digit[i] = '0';
}
first = true;
odd = true;
}
public boolean hasNext() {
// 計算第一個1的位置
for(count = 0;
(count < digit.length) && (digit[count] == '0');
count++) ;
return count != digit.length - 1;
}
public char[] next() {
if(first) {
first = false;
return digit;
}
if(odd)
chargeBit(digit, 0);
else {
// 最後一個Gray Code 嗎
if(hasNext())
chargeBit(digit, count+1);
}
odd = ((odd == true) ? false : true);
return digit;
}
private void chargeBit(char[] digit, int i) {
digit[i] = ((digit[i] == '0') ? '1' : '0');
}
public static void main(String[] args) {
GrayCode code = new GrayCode(4);
while(code.hasNext()) {
char[] digit = code.next();
for(int i = digit.length - 1; i >= 0; i--)
System.out.print(digit[i]);
System.out.println();
}
}
}