标签:
Description
Input
Output
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
URAL 2029 Towers of Hanoi Strike Back 汉诺塔,从初始状态到任意给出状态需要的次数
标签:
原文地址:http://blog.csdn.net/prolightsfxjh/article/details/52076323