UVA 10795 A Different Task

来源:互联网 发布:美工目前发展状况 编辑:程序博客网 时间:2024/04/30 20:46

刘汝佳的训练指南上的例题,自己想不出来.

思路:

考虑编号最大的盘子.如果这个盘子最初始局面和目标局面位于同一根柱子.那么也这根柱子不用移动.所以要找出所有盘子中不在目标局面的编号最大的盘子k.

在移动k之前,k所在的柱子k的上面必须为空,并且k要去的柱子final的最上面的盘子编号也必须大于k,所以如果k上面还有盘子,那么这个盘子必须去 除这

两根柱子外的那根柱子上.

称k移动过去后的局面为参考局面.

根据对称性,我们只需求出初始局面和目标局面移动成参考局面的步数之和加上1(k移动到目标柱子)就是答案了.

用A[k]来代表各个盘子的初始位置,k表示当前要移的盘子,final表示k要去的盘子.

则可以写个函数f(A, k, final)来表示.

如果当前盘子位置A[k] == final 表示当前盘子已经在目标位置上,只需要把 1 2 .. k  - 1 个盘子移动到目标位置final上就可以了

否则则要先把1 2 .. k - 1 移动到指定位置(即不是k所在的柱子,也不是k要去的柱子),再把k移动到目标柱子final,再把1 2 .. k - 1 移动到目标柱子(这里就用到了汉诺塔的结论需要2^(k - 1)步 )

#include <iostream>#include <cstdio>using namespace std;const int maxn = 70; int n, start[maxn], finish[maxn];long long f1(int k, int tar){//A[i]表示初始i盘子所在的柱子    if(k == 0) return 0;    if(A[k] == tar)return f(A, k -1, tar);//当前盘子已经在目标柱子上,不需要移动了,只需要把k - 1个盘子移动到目标柱子    return f(A, k - 1, 6 - A[k] - tar) + (1L << ( k - 1));//当前柱子不在目标柱子上,首先把1 2 ...k - 1个盘子移动到指定位置(即不是当前柱子,也不是目标柱子到柱子6 - A[k] -tar),然后把k移动到目标柱子,再把1 2 .. k - 1个盘子移动到目标柱子上(也就是汉诺塔的结论需要2^(k - 1) - 1步}int main(){    int cas = 1;    while(scanf("%d", &n) == 1 && n){         for(int i = 1; i <= n; ++i)                scanf("%d", &start[i]);        for(int i = 1; i <= n; ++i)                scanf("%d", &finish[i]);        int k = n;        while(k >= 1 && start[k] == finish[k])--k;//找出不最目标柱子上到最大盘子编号        long long ans = 0;        if(k >= 1){             int other = 6 - start[k] - finish[k];            ans = f(start, k - 1, other) + f(finish, k - 1, other) + 1;        }           printf("Case %d: %lld\n", cas++, ans);    }       return 0;}


原创粉丝点击