2024百度之星第二场初赛 BD202409还原汉诺塔 打表

原题再现

汉诺塔问题是一个十分经典的问题。

即有三根杆子 A,B,C。A 杆上有 n 个穿孔圆盘,盘的尺寸由下到上依次变小。要求按下列规则将所有圆盘移至 C 杆:
1.每次只能移动一个圆盘
2.大盘不能叠在小盘上面

由于汉诺塔问题最优步骤实际上是需要 2^{n}-1 步,可以证明每一步实际上是固定的。

所以小度想要知道,对于第 k 步后而言,汉诺塔此时每个圆盘处于哪个杆子。

在线汉诺塔游戏-汉诺塔算法可视化

题目解答

打表代码

#include<bits/stdc++.h>
using namespace std;
int n;string s;
int step;
stack<int>A;stack<int>B;stack<int>C;
map<stack<int>*,char> name;
void move(int k,stack<int>&from,stack<int>&to,stack<int>&mid){
	if(k==1){
		step++;
		s[from.top()-1]=name[&to];
		to.push(from.top());from.pop();
		int c=step;string r="";
		while(c){
			if(c%2)r+='1';else r+='0';
			c/=2;
		}
		while(r.size()<n)r+='0';
		cout<<r<<endl<<s<<endl;
		return;
	}
	move(k-1,from,mid,to);
	move(1,from,to,mid);
	move(k-1,mid,to,from);
}
signed main(){
	cin>>n;
	for(int i=0;i<n;i++)s+='A';
	cout<<setw(n)<<setfill('0')<<""<<endl<<s<<endl;
	name[&A]='A';name[&B]='B';name[&C]='C';
	for(int i=n;i>=1;i--)A.push(i);
	move(n,A,C,B);
	return 0;
}

输入5,我们来找规律。

00000
AAAAA
10000
CAAAA
01000
CBAAA
11000
BBAAA
00100
BBCAA
10100
ABCAA
01100
ACCAA
11100
CCCAA
00010
CCCBA
10010
BCCBA
01010
BACBA
11010
AACBA
00110
AABBA
10110
CABBA
01110
CBBBA
11110
BBBBA
00001
BBBBC
10001
ABBBC        
01001
ACBBC
11001
CCBBC
00101
CCABC
10101
BCABC
01101
BAABC
11101
AAABC
00011
AAACC
10011
CAACC
01011
CBACC
11011
BBACC
00111
BBCCC
10111
ABCCC
01111
ACCCC
11111
CCCCC

其实最重要的是,不同位置上0和1分别对应的是ABC中的哪个字母。

可以发现,连续的0或者连续的1对应的字母相同。而隔着奇数个0的1对应的字母不同,隔着偶数个0的1对应的字母相同,隔着奇数个1的0对应的字母不同,隔着偶数个1的0对应的字母相同。

这样,只需要确定一个位置对应的字母,其他位置就可以推断出来了。

发现最后一个位置的规律很明显,即0对应A,1对应B,我们完全可以从最后一个位置朝前推出所有位置对应的字母。

#include<bits/stdc++.h>
using namespace std;
int n,p;string s;
char ans[100005];
map<char,char>t={{'0','A'},{'1','C'}};
signed main(){
	cin>>n>>s;
	while(p<n){
		int ls=0;char c=s[p];
		while(s[p]==c&&p<n){
			ans[p]=t[c];
			ls++;p++;
		}
		if(ls%2)t[s[p]]=char('A'+'B'+'C'-t['0']-t['1']);
	}
	for(int i=n-1;i>=0;i--)cout<<ans[i];
	return 0;
}

哈哈哈,我感觉这个代码真的是非常简洁!我非常高兴!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值