在一组数的编码中,若任意两个相邻的代码只有一位二进制数不同,则称这种编码为格雷码(Gray Code),另外由于第一个与最后一个之间也仅一位数不同,即“首尾相连”,因此又称循环码或反射码。
例如一段比较经典的格雷码就是:
0 1 3 2 6 7 5 4
小沙有一段自己的编码数列,他发现他的编码数列与格雷码很像,它的任意两个相邻的编码只有一位二进制数不同,但是它的第一个与最后一个之间不一定仅有一位数不同。
现在小沙给出在他编码意义下所有小于�n的偶数位在普通编码十进制的值,需要你猜想小沙编码意义下 [0,�−1][0,n−1] 在普通编码十进制的值。
题目保证 �=2�n=2k , �k 为一个正整数,你需要保证你猜想的数字 �x ,0≤�<�0≤x<n。
输出任意合法方案皆可,保证存在一个合法方案。
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
using namespace std;
const int N = 1e5+10;
int n,flag;
int vis[N];
vector<int> res;
vector<int> q[N];
int calu(int x){
int cnt=0;
while(x){
cnt++;
x-=x&-x;
}
return cnt;
}
void dfs(int cnt){
if(res.size()==n/2){
flag=1;
return ;
}
for(int i=0;i<q[cnt].size();i++){
if(vis[q[cnt][i]]) continue;
res.push_back(q[cnt][i]);
vis[q[cnt][i]]=1;
dfs(cnt+1);
vis[q[cnt][i]]=0;
if(flag) return ;
res.pop_back();
}
}
int main()
{
cin>>n;
int maxs=log2(n)-1,cnt=0;
vector<int> g(n/2+1);
for(int i=1;i<=n/2;i++) cin>>g[i];
for(int i=2;i<=n/2;i++){
for(int j=0;j<=maxs;j++){
int ans=g[i-1]^(1<<j);
if(calu(g[i]^ans)==1){
q[cnt].push_back(ans);
}
}
cnt++;
}
for(int i=0;i<=maxs;i++){
int ans=g[n/2]^(1<<i);
q[cnt].push_back(ans);
}
dfs(0);
cnt=0;
for(int i=1;i<=n/2;i++)
cout<<g[i]<<" "<<res[cnt++]<<" ";
}