Hanoi Towers


题目描述:

H. Hanoi Towers

Time Limit: 5000ms

Memory Limit: 65536KB
64-bit integer IO format: %lld Java class name: Main

Submit Status PID: 3691

The “Hanoi Towers” puzzle consists of three pegs (that we will name A, B, and C) with n disks of different diameters stacked onto the pegs. Initially all disks are stacked onto peg A with the smallest disk at the top and the largest one at the bottom, so that they form a conical shape on peg A.

A valid move in the puzzle is moving one disk from the top of one (source) peg to the top of the other (destination) peg, with a constraint that a disk can be placed only onto an empty destination peg or onto a disk of a larger diameter. We denote a move with two capital letters — the first letter denotes the source disk, and the second letter denotes the destination disk. For example, AB is a move from disk A to disk B.

The puzzle is considered solved when all the disks are stacked onto either peg B (with pegs A and C empty) or onto peg C (with pegs A and B empty). We will solve this puzzle with the following algorithm.

All six potential moves in the game (AB, AC, BA, BC, CA, and CB) are arranged into a list. The order of moves in this list defines our strategy. We always make the first valid move from this list with an additional constraint that we never move the same disk twice in a row.

It can be proven that this algorithm always solves the puzzle. Your problem is to find the number of moves it takes for this algorithm to solve the puzzle using a given strategy.

Input

The input file contains two lines. The first line consists of a single integer number n (1 ≤ n ≤ 30) — the number of disks in the puzzle. The second line contains descriptions of six moves separated by spaces — the strategy that is used to solve the puzzle.

Output

Write to the output file the number of moves it takes to solve the puzzle. This number will not exceed 1018.

Sample Input

1

3
AB BC CA BA CB AC

2

2
AB BA CA BC CB AC

Sample Output

1 7

2 5

题解:

挺好的一道汉罗塔的题.
汉罗塔很显然是一个递推.
我们试着去往它上面靠.
i的规模分成1(大)和i-1(小),i-1的移动和那个大的有关吗?我们利用f[i][a][b]的最小步数定义,就是只有i规模的盘子从a移到b,并且中间不能够全部移动到c的步数!!!这个定义很重要. 那么回到刚才的,i-1从a移动到b和i的那个大盘子是没有关系的,因为是最小定义.并且题目我们也恰好发现了不能重复移动一个盘子两次的规定恰好符合我们的抽象. 那么我们就完全转化成了连个盘子的汉罗塔,之后就是暴力枚举移动哪一个盘子,只是移动的代价不一样,并且每次要找时间序最小的,并且还要可以放在上面.

重点:

汉罗塔一直推递推.看成1+(n-1)

代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <ctype.h>
#include <limits.h>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <queue>
#include <map>
#include <stack>
#include <set>
#include <bitset>
#define CLR(a) memset(a, 0, sizeof(a))
#define REP(i, a, b) for(int i = a;i < b;i++)
#define REP_D(i, a, b) for(int i = a;i <= b;i++)

typedef long long ll;

using namespace std;

const int maxn = 100+10;
const ll INF = 2e18;
ll f[maxn][4][4];
int from[10], to[10];
int b[4];
int n;

void solve(int n)
{
    for(int sta = 0; sta < 3; sta++)
    {
        for(int i = 0; i<3; i++)
            f[n][sta][i] = INF;
        b[0] = 0;
        b[1] = 0;
        b[2] = 0;
        b[sta] = 3;
        int used = -1;
        ll ans = 0;
        while(1)
        {
            ll step = INF;
            int fromb = -1, tob = -1, tag = -1;
            for(int i = 0; i<3; i++)
            {
                if(b[i]==1&&used!=1)
                {
//                    for(int j = 0; j<3; j++)
//                    {
//                        if(j==i)
//                            continue;
//                        if(f[1][i][j]<step&&b[j]!=2)
//                        {
//                            step = f[1][i][j];
//                            fromb = i;
//                            tob = j;
//                            tag = 1;
//                        }
//                    }



                    for(int k = 0;k<6;k++)
                    {
                        if(from[k]==i&&b[to[k]]!=2)
                        {
                            step = 1;
                            fromb = i;
                            tob = to[k];
                            tag = 1;
                            break;
                        }
                    }
                }
                else if((b[i]==2||b[i]==3)&&used!=2)
                {
                    for(int j = 0; j<3; j++)
                    {
                        if(j==i)
                            continue;
                        if(f[n-1][i][j]<step)
                        {
                            step = f[n-1][i][j];
                            fromb = i;
                            tob = j;
                            tag = 2;
                        }
                    }
                }
            }
            if(step==INF)
                break;
            ans += step;
            b[fromb] -= tag;
            b[tob] += tag;/
            used = tag;
            int keypos = -1;
            for(int i = 0; i<3; i++)
            {
                if(b[i]==3)
                {
                    keypos = i;
                    break;
                }
            }
            if(keypos!=-1)
            {
                f[n][sta][keypos] = min(f[n][sta][keypos], ans);
                break;
            }
        }
    }
}

void gao()
{
    for(int sta = 0; sta < 3; sta++)
    {
        f[1][sta][0] = INF;
        f[1][sta][1] = INF;
        f[1][sta][2] = INF;
        for(int k = 0; k<6; k++)
        {
            if(from[k]==sta)
            {
                f[1][sta][to[k]] = 1;
                break;
            }
        }
    }
//    for(int i = 0; i<3; i++)
//    {
//        for(int j = 0; j<3; j++)
//        {
//            printf("%d  %d  %d %d\n", 1, i, j, f[1][i][j]);
//        }
//    }
    for(int i = 2; i<=n; i++)
    {
        solve(i);
        //if(i==2)
//        for(int k = 0; k<3; k++)
//        {
//            for(int j = 0; j<3; j++)
//            {
//                printf("%d  %d  %d %lld\n", i, k, j, f[i][k][j]);
//            }
//        }
    }
    ll ans = min(f[n][0][1], f[n][0][2]);
    printf("%lld\n", ans);
}

char str[10];
int main()
{
   // freopen("8Hin.txt", "r", stdin);
    //freopen("8Hout.txt", "w", stdout);
    while(scanf("%d", &n) != EOF)
    {
        for(int k = 0; k<6; k++)
        {
            scanf("%s", str);
            from[k] = str[0]-'A';
            to[k] = str[1]-'A';
        }
        gao();
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值