原题再现
汉诺塔问题是一个十分经典的问题。
即有三根杆子 A,B,C。A 杆上有 n 个穿孔圆盘,盘的尺寸由下到上依次变小。要求按下列规则将所有圆盘移至 C 杆:
1.每次只能移动一个圆盘
2.大盘不能叠在小盘上面
由于汉诺塔问题最优步骤实际上是需要 -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;
}
哈哈哈,我感觉这个代码真的是非常简洁!我非常高兴!