F - Towers of Hanoi Strike Back
Time Limit:1000MS Memory Limit:65536KB 64bit IO Format:%I64d
& %I64u
Submit Status Practice URAL
2029
Description
The Tower of Hanoi puzzle was invented by French mathematician édouard Lucas in the second half of the 19th century. Here is its formulation.
There are three rods, denoted by the letters A, B, and C, and n disks of different integer sizes from 1 to n. Initially the disks are stacked
in ascending order of size on rod A, the smallest at the top, thus making a conical shape. Each move consists of taking the upper disk
from one of the rods and placing it on top of the stack at another rod, with the following condition satisfied: no disk may be placed on
top of a smaller disk. The objective of the puzzle is to move the entire stack to rod B in the smallest possible number of moves. The auxiliary rod C can be used in the process.
The state of the rods at each time can be described by a string of n letters A, B, and C: the letter at position i denotes the rod where the disk of size i is at that time. For example, the initial
state is given by the string containing letters A only, and the final state is described by the string consisting of letters B. The converse is also true: any such string uniquely describes a valid state of the rods, because the order of disks on a rod is
uniquely defined by their size.
Imagine that you are required to pass from the initial state, where all the disks are on rod A, to some prescribed state. What is the
smallest number of moves in which this can be done?
Input
The first line contains an integer n (1 ≤ n ≤ 50).
In the second line you are given n uppercase English letters A, B, C, which describe the final state.
Output
If it is impossible to obtain the final state from the initial state, output “-1” (without quotation marks). Otherwise, output the minimum number of moves. It is guaranteed that, if there is an answer, it does not exceed 10 18.
Sample Input
input | output |
---|---|
1 A |
0 |
4 BBBB |
15 |
7 BCCBABC |
95 |
Source
UESTC 2016 Summer Training #17 Div.2
My Solution
汉诺塔, 得到从初始状态到任意给出状态需要的次数的O(n)算法, 记结论吧??
比如要得到 BCCBABC
则对于原始的AAAAAAA
第一次令 res = ‘A‘, 然后对于给出的state从大的往小的开始扫, 当前是C所以第7个A变成C, ans += 2^(7 - 1), 然后res = ‘B‘, 也就是剩余的移到B上,
然后第二个需要到B上,且已经在B上, 所以不用管, 继续访问下一位
然后是A, 这个时候把当期大小的盘在B上, 所以移到A上, ans += 2^(5 - 1), 然后res = ’C‘, 剩余的全都移到第三个柱子’C‘上。
依次这样下去就好了
比较当前盘需要的在哪个柱子上和当前在那个柱子上, 如果恰好在则直接访问下一个盘子, 如果不是则把该盘移过去 ans += 2^i ( 0 <= i < n), 剩余的盘全移到第三个柱子上
把AAAAAAA.....从右往左, 全部变成state, 就可以得到答案了
此外注意点
用 1<<i得到 2^i次时,如果i很大, 比如50, 这个时候integer 溢出了, 用 (LL)(1<<50)也达不到效果, 还是得到数据丢失的integer大小的数,
然后用了cmath里的那个不大靠谱的pow, ans += (LL)pow(2, i);就可以得到 64位的整数了
复杂度 O(n)
#include <iostream> #include <cstdio> #include <cmath> using namespace std; typedef long long LL; const int maxn = 1e2 + 8; char val[maxn]; int main() { #ifdef LOCAL freopen("a.txt", "r", stdin); //freopen("b.txt", "w", stdout); int T = 4; while(T--){ #endif // LOCAL LL n, ans = 0; char res = 'A'; scanf("%I64d", &n); scanf("%s", val); for(LL i = n - 1; i >= 0; i--){ if(res != val[i]){ ans += (LL)pow(2, i); //cout<<ans<<endl; if(res == 'A'){ if(val[i] == 'B') res = 'C'; else res = 'B'; } else if(res == 'B'){ if(val[i] == 'A') res = 'C'; else res = 'A'; } else if(res == 'C'){ if(val[i] == 'A') res = 'B'; else res = 'A'; } } if(ans < 0 || ans > 1e18) break; } if(ans < 0 || ans > 1e18) printf("-1"); printf("%I64d", ans); #ifdef LOCAL printf("\n"); } #endif // LOCAL return 0; }
Thank you!
------from ProLights