在奶牛回家休息和娱乐之前,Farmer John 希望它们通过玩游戏获得一些智力上的刺激。游戏板由 nn 个相同的孔组成,这些孔最初
都是空的
。一头母牛要么用石头盖住一个洞,要么揭开一个先前被盖住的洞。
游戏状态
的定义是哪些洞被石头覆盖,哪些洞没有覆盖。游戏的目标是让奶牛准确地到达每个可能的游戏状态一次,然后返回到所有洞都没有覆盖的状态。以下是他们其中一次游戏的示例(空的洞用
O
表示,用石头盖住的洞用
X
表示):
时间 | 洞 1 | 洞 2 | 洞 3 | 描述 |
---|---|---|---|---|
00 | O | O | O | 一开始所有的洞都是空的 |
11 | O | O | X | 盖上洞 3 |
22 | X | O | X | 盖上洞 1 |
33 | X | O | O | 打开洞 3 |
44 | X | X | O | 盖上洞 2 |
55 | O | X | O | 打开洞 1 |
66 | O | X | X | 盖上洞 3 |
77 | X | X | X | 盖上洞 1 |
现在牛被卡住玩不下去了!他们必须打开一个洞,不管他们打开哪个洞,他们都会到达一个他们已经到达的状态。例如,如果他们从第二个洞中取出岩石,他们将到达他们在时间 22 已经访问过的状态(
X O X
)。
下面是一个 3 个孔的有效解决方案:
时间 | 洞 1 | 洞 2 | 洞 3 | 描述 |
---|---|---|---|---|
00 | O | O | O | 一开始所有的洞都是空的 |
11 | O | X | O | 盖上洞 2 |
22 | O | X | X | 盖上洞 3 |
33 | O | O | X | 打开洞 2 |
44 | X | O | X | 盖上洞 1 |
55 | X | X | X | 盖上洞 2 |
66 | X | X | O | 打开洞 3 |
77 | X | O | O | 打开洞 2 |
88 | O | O | O | 打开洞 1,恢复到原来的状态 |
现在,奶牛们厌倦了这个游戏,它们想找你帮忙。
给定 nn,求游戏的有效解决方案序列。如果有多个解决方案,则返回
任意一个
。
输入格式
仅一行,一个整数 nn。
输出格式
共 2^n+12n+1 行,每行一个长度为 nn 的字符串,其中只包含字符
O
和
X
,该行中的第 ii 个字符表示第 ii 个孔在此状态下是被覆盖还是未覆盖,第一行和最后一行必须全部都是
O
。
输入输出样例
输入 #1
复制
3
输出 #1
复制
OOO OXO OXX OOX XOX XXX XXO XOO OOO
思路:如果去掉两个全都是0的序列的话就是有2^n-1个序列
状态用1~2^n的二进制数表示
然后我们就找1~2^n的全排列中满足相邻的两个数相差一位的序列
用一个数来记录一下,找到了就更改一下,每次递归首先判断一下是否已经更改,如果更改了就直接返回
用一个数组来记录2^n-1个状态的方案序列
然后每次递归记录的是当前搜到第几个状态,如果搜到了最后的先输出全是0再输出序列再输出全是0
因为我们要找的是1~2^n的二进制表示的状态,为了避免搜到0我们先把0标记为已经用过
然后我们开始从第一个序列递归
设每次递归到第u个状态的数,那我们就一位一位看第u-1个状态的数
如果第i位的数是1就减掉第i位的1递归,如果是0就加上第i位上的1递归
具体见代码注释
/*
.----------------. .----------------. .----------------. .----------------.
| .--------------. || .--------------. || .--------------. || .--------------. |
| | ________ | || | _________ | || | ____ ____ | || | ____ | |
| | |_ ___ `. | || | |_ ___ | | || ||_ \ / _|| || | .' `. | |
| | | | `. \ | || | | |_ \_| | || | | \/ | | || | / .--. \ | |
| | | | | | | || | | _| _ | || | | |\ /| | | || | | | | | | |
| | _| |___.' / | || | _| |___/ | | || | _| |_\/_| |_ | || | \ `--' / | |
| | |________.' | || | |_________| | || ||_____||_____|| || | `.____.' | |
| | | || | | || | | || | | |
| '--------------' || '--------------' || '--------------' || '--------------' |
'----------------' '----------------' '----------------' '----------------'
*/
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
#include<set>
#include<map>
#include<queue>
#include<deque>
#include<cmath>
#include<stack>
#define int long long
#define lowbit(x) x&(-x)
#define PI 3.1415926535
#define endl "\n"
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
int gcd(int a,int b) {
return b? gcd(b,a%b):a;
}
/*
int dx[8]={-2,-2,-1,1,2,2,-1,1};
int dy[8]={-1,1,2,2,1,-1,-2,-2};
int dx[4]={0,-1,0,1};
int dy[4]={-1,0,1,0};
int dx[8]={-1,1,0,0,-1,-1,1,1};
int dy[8]={0,0,-1,1,-1,1,-1,1};
*/
//int e[N],ne[N],h[N],idx,w[N];
/*void add(int a,int b,int c){
e[idx]=b;
w[idx]=c;
ne[idx]=h[a];
h[a]=idx++;
}
*/
const int N=1<<15+5;
int m,f,n;
int c[N];//记录每个状态是否出来过
int a[N];
void dfs(int u){//记录当前状态的下标
if(f)return ;
if(u==m){
f=1;
for(int i=0;i<n;i++)cout<<"O";
cout<<endl;
for(int i=1;i<m;i++){
for(int j=0;j<n;j++){
if((a[i]>>j)&1)cout<<"X";
else cout<<"O";
}
cout<<endl;
}
for(int i=0;i<n;i++)cout<<"O";
cout<<endl;
return ;
}
int now;
for(int i=0;i<n;i++){
if((a[u-1]>>i)&1){
now=a[u-1]-(1<<i);
}else now=a[u-1]+(1<<i);
if(!c[now]){//如果没被用过
c[now]=1;//标记一下
a[u]=now;//现在这个状态是now
dfs(u+1);//递归下一位
c[now]=0;//如果找不到正确答案那就回溯
a[u]=0;
}
}
return ;
}
void sove(){
cin>>n;
m=1<<n;
c[0]=1;
dfs(1);
}
signed main(){
sove();
return 0;
}