AtCoder Grand Contest 031_C - Differ by 1 Bit

题目链接、

题意:

给你一个n,a,b

让你构造一个序列,长度为2^n,以a开始以b结尾,中间任意两个相邻的元素二进制相差1位

例如 

2 1 3

输出

1 0 2 3

即,1开始,3结束,2^2个数01,00,10,11,相邻元素转化为二进制严格相差一位

题解:

首先,

一个n位的二进制数,与他严格相差一位的数一共有n个

例如:

与00相差一位的有10和01

与000相差一位的有100,010,001

考虑缩小问题规模,即n位与n-1位的关系

这里有一个很巧妙的想法就是n维超立方体

举例

一个2维超立方体(正方形)

00 01
10 11

 

3维(正方体)

 

先遍历n-1维超立方体然后再遍历n维超立方体(2个n-1组成1个n维)

就这样,可以写出一个dfs

代码源自、

#include
using namespace std;
typedef long long ll;
const int maxn = 1e5+7;
int n,a,b,sum;
void dfs(int x,int y,int ban){
    if(__builtin_popcount(ban^sum) == 1){printf("%d %d ",y,x^y);return;}
    for(int i=0;i>i))&1 && (x>>i)&1)
        for(int j=0;j>j))&1 && i!=j){
            dfs(1<

__builtin_popcount(x)表示求x在二进制上有几个1 

ban是一个标记变量,即,考虑的那些位在二进制上表现为1,那么在__builtin_popcount(ban^sum) == 1

就是说当ban和sum(111111,即n个1)相差只有1位,也就是说已经考虑完所有位数(除当前位)的时候可以判断输出了

 

 

想了好久这个东西怎么理解,最后我妥协了,模拟了下代码,大概懂了,但是,下次做到类似的题,大概还是不会、、

n = 3, a = 0 , b = 7

dfs层数 x y ban cout i j
1 111 000 000 - 0 1
2 010 000 001 - 1 2
3 100 000 011 000,010 - -
3 100 110 011 110,010 - -
2 100 011 001 - 2 1
3 010 011 011 011,001 - -
3 010 101 011 101,111 -

-

即输出

YES
0 4 6 2 3 1 5 7

每层dfs中有两个dfs,容易看出(模拟出(瞎猜出)),这是拆分n维为两个n-1维立方体

 

 

你可能感兴趣的:(思维(抖啊,抖啊,抖个机灵儿))