UVA-10795
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; }