知识点:递归
递归思路:
设开始时盘子全在 A 柱上,要把盘子移到 C 柱上,中间柱是 B。
首先,我们来判断一下是不是初末状态,即盘子全在 A 上或全在 C 上,这一定是合法的。
其次,我们要对每种状态中最大的那个盘子的位置进行判断。因为我们知道,汉诺塔最大的那个盘子不可能在 B 上,只可能在 A 或者 C 上面。所以有3种情况:
case 1:如果在 B 上面,一定是非法的,即可停止判断。
case 2:如果在 A 上面,说明他还没有放在 C 上,当前状态的前一个状态是想把除最大的以外的其他所有盘子放到 B
上,然后就可以把 A 放到 C 上了。由于这两个状态的方向不同(当前状态的方向是 A->C ,而前一个状态的方
向是 A->B ),所以我们在对前一个状态进行讨论之前要进行更新,把 B 跟 C 互换。
case 3:如果在 C 上面,这时候倒数第二大的不是在 B 上就是在 C 上,我们要把倒数第二大的以及其他的都放到 C
上,这个状态的方向是 B->C ,跟前一状态不同,所以也要进行更新,把 A 跟 B 互换。
#include <cstdio>
struct pole {
int num; //当前柱子上的盘子数目
int dish[64]; //从下到上的盘子
int first; //记录当前柱子上在当前状态下的第一个盘子的位置
} p[3];
bool scan_d(int &n) //整数输入外挂,减少时间
{
char i;
bool I=0;
i=getchar();
if(i==EOF) return 0;
while(i!='-'&&(i<'0'||i>'9'))
i=getchar();
if(i=='-') I=1,n=0;
else n=i-'0';
while(i=getchar(),i>='0'&&i<='9')
n=n*10+i-'0';
if(I) n=-n;
return 1;
}
int main() {
int t;
scan_d(t);
while (t--) {
int n;
scan_d(n);
for (int i = 0; i < 3; ++i) {
scan_d(p[i].num);
for (int j = 0; j < p[i].num; ++j) {
scan_d(p[i].dish[j]);
}
p[i].first = 0;
}
//start、mid、end分别指向开始柱子、中间柱子、目的柱子
pole *start = p, *mid = p+1, *end = p+2;
while (true) {
if (start->num == n || end->num == n) {
puts("true");
break;
}
if (mid->num > 0 && mid->dish[mid->first] == n) {
puts("false");
break;
}
if (start->num > 0 && start->dish[start->first] == n) {
--n;
--start->num;
++start->first;
pole *temp = mid;
mid = end;
end = temp;
continue;
}
if (end->num > 0 && end->dish[end->first] == n) {
--n;
--end->num;
++end->first;
pole *temp = start;
start = mid;
mid = temp;
}
}
}
return 0;
}
![](http://hi.csdn.net/attachment/201111/10/0_1320893263Y5Lh.gif)
![](http://hi.csdn.net/attachment/201111/10/0_13208932786A8e.gif)