UVA-10795

uva传送门

A Different Task

新型汉诺塔, 题意:将初始状态的汉诺塔变成结束状态

输入n个盘子(盘子从小到大)所在的柱子位置 (1 2 3代表 A B C柱子),

假定 结束状态某个柱子上的最大盘子为 x, 如果初始状态x已经在对应柱子上了 那么一定不需要移动, 因为盘子是从小到大放置的, x已经在结束状态上位置正确  移动是多余没有必要的,

然后可以假定有一个中间状态(6-初始-结束),我们如果需要把 k 个盘子从初始状态变成结束状态的话 可以先把 k -1 个盘子移动到 中间盘子上, 再将 k-1 个盘子移动到 结束状态 最后移动第 k 个盘子即可,    ans =    f(start, k-1, mid) + f(final, k-1, mid) +1   

 //因为中间状态是假想的,从中间状态移动 k-1 个盘子到 结束状态 等于  结束状态移动 k-1 个盘子到中间状态, 所以 用 结束状态 移动 k-1 个盘子来表示 

 然后这个时候就可以递归求解    f(p, k,  mid) 代表从 p 状态移动 k 个盘子到 mid 上, 可以转化为先将 k-1 个未排序的盘子移动到 中间状态, 然后中间状态 将 k-1 个已排序的盘子移动到结束状态 + 1 (移动 第k个盘子)

  因为汉诺塔的已知结论 把 n 个已排序的盘子全部移动到另一个柱子上最少需要  2n-1步,  所以 f(p, k, mid) = f(p, k-1, mid) + (1LL<<(k-1))-1+1

  如果 k 小于 0, 则不需要移动

#include<bits/stdc++.h>

using namespace std;

#define _for(i,a,b) for(int i = (a); i < (b); i++)
#define _rep(i,a,b) for(int i = (a); i <= (b); i++)
#define all(v) (v).begin(), (v).end()
#define ll long long

ll f(vector<int> p, int k, int mid) {
    if(k < 1) return 0;
    if(p[k] == mid) return f(p, k-1, mid);
    return f(p, k-1, mid) + (1LL<<(k-1));
}

void uva10795() {
    int n, kase = 1; 
    while(cin >> n and n) {
        vector<int> a(n+1), b(n+1);
        _rep(i,1,n) cin >> a[i];
        _rep(i,1,n) cin >> b[i];
        int k = n;
        while(k > 0 and a[k] == b[k]) k--;
        ll ans = 0;
        if(k > 0) {
            int mid = 6-a[k]-b[k];
            ans = f(a, k-1, mid) + f(b, k-1, mid) + 1;
        } cout << "Case " << kase++ << ": " << ans << "\n";
    }
    return;
}

int main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
    uva10795();
    return 0;
}

 

posted @ 2020-09-15 08:20  163467  阅读(116)  评论(0编辑  收藏  举报