HDU 1997 - 汉诺塔VII

知识点:递归

递归思路:

设开始时盘子全在 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;
}


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值