uva 10795
分类: 递归与模拟
题意: 汉诺塔问题改版,求对于给定状态的汉诺塔问题,到指定目标状态,需要多少次操作
输入: 盘子数目n,每个盘子所在的架子编号
输出: 移动次数
解法:
经典汉诺塔问题,f(n) = 2 * f(n - 1) + 1;其中f(1) = 1,将1-n的盘子移动到另外一个盘子需要的次数
这个题怎么做,想了好一会没有特别好的思路,参考了书上的解法
初始状态 ----> 中间状态(必须经由) ----> 目标状态
由于可逆性,可以改为 初始状态 ----> 中间状态 <---- 目标状态
递归函数设计(关键)
f(array* start, k, final)表示,将初始状态为array的盘子中 1---k号盘子移动到 final柱子所需要的次数
递归求解,中间直接用到经典汉诺塔问题公式
#include <iostream> #include <vector> #include <map> #include <list> #include <set> #include <deque> #include <stack> #include <queue> #include <algorithm> #include <cmath> #include <cctype> #include <cstdio> #include <iomanip> #include <cmath> #include <cstdio> #include <iostream> #include <string> #include <sstream> #include <cstring> #include <queue> using namespace std; ///宏定义 const int INF = 990000000; const int MAXN = 62; const int maxn = MAXN; ///全局变量 和 函数 typedef long long LL; LL n; LL startArr[maxn]; LL finishArr[maxn]; //将起始状态sta, 1---k号移动移动到另外一个柱子上 LL f(LL* sta, LL k, LL final) { if (k == 0) return 0; if (k == 1) { if (sta[k] == final) return 0; else return 1; } if (sta[k] == final) return f(sta, k - 1, final); return f(sta, k - 1, 6 - final - sta[k]) + pow((long double)2, (long double)(k - 1)); } LL cal() { int i; for(i = n; i >= 1; i--) { if (startArr[i] != finishArr[i]) break; } if (i == 0) return 0; else return f(startArr, i - 1, 6 - startArr[i] - finishArr[i]) + f(finishArr, i - 1, 6 - finishArr[i] - startArr[i]) + 1; //注意是i不是i-1 WA了一次 } int main() {///变量定义 LL cases = 1; while (scanf("%lld", &n) != EOF && n) { for (int i = 1; i <= n; i++) scanf("%lld", &startArr[i]); for (int i = 1; i <= n; i++) scanf("%lld", &finishArr[i]); LL ans = cal(); printf("Case %lld: %lld\n", cases++, ans); } ///结束 return 0; }