P6183 [USACO10MAR] The Rock Game S

在奶牛回家休息和娱乐之前,Farmer John 希望它们通过玩游戏获得一些智力上的刺激。游戏板由 nn 个相同的孔组成,这些孔最初都是空的。一头母牛要么用石头盖住一个洞,要么揭开一个先前被盖住的洞。游戏状态的定义是哪些洞被石头覆盖,哪些洞没有覆盖。游戏的目标是让奶牛准确地到达每个可能的游戏状态一次,然后返回到所有洞都没有覆盖的状态。以下是他们其中一次游戏的示例(空的洞用 O 表示,用石头盖住的洞用 X 表示):

时间洞 1洞 2洞 3描述
00OOO一开始所有的洞都是空的
11OOX盖上洞 3
22XOX盖上洞 1
33XOO打开洞 3
44XXO盖上洞 2
55OXO打开洞 1
66OXX盖上洞 3
77XXX盖上洞 1

现在牛被卡住玩不下去了!他们必须打开一个洞,不管他们打开哪个洞,他们都会到达一个他们已经到达的状态。例如,如果他们从第二个洞中取出岩石,他们将到达他们在时间 22 已经访问过的状态(X O X)。

下面是一个 3 个孔的有效解决方案:

时间洞 1洞 2洞 3描述
00OOO一开始所有的洞都是空的
11OXO盖上洞 2
22OXX盖上洞 3
33OOX打开洞 2
44XOX盖上洞 1
55XXX盖上洞 2
66XXO打开洞 3
77XOO打开洞 2
88OOO打开洞 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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值