原题链接
题意:找最小公共祖先(离两个点最近的公共祖先)
把每个节点看成二进制数,以1为根的完全二叉树,每个节点的父节点的编号等于自己的编号除以2。二进制数除2 <=> 二进制数右移1位
解题思路:
用string读入16进制字符串,转化为二进制字符串,找到两个二进制字符串的最长前缀,将该前缀转化为16进制字符串即为答案
做题时进入的误区:找两个二进制字符串的最长前缀,为了方便,找了16进制的前缀。当2进制右移的位数%4 = 0 时是等价的,反之,二进制位的权值发生变化,4个二进制位对应的16进制为也要发生变化 如
二进制数 1111 对应16进制 f
右移一位 0111 对应16进制 7 != f
另外,通过本次,学了个2进制与16进制互转的模板(详情看代码)
#include <iostream>
#include <cstdio>
using namespace std;
string dx[] = {"0", "1", "10", "11", "100", "101", "110", "111", "1000", "1001", //(首位)16进制转2进制
"1010", "1011", "1100", "1101", "1110", "1111"};
string dy[] = {"0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111", "1000", "1001", //(非首位)16进制转2进制
"1010", "1011", "1100", "1101", "1110", "1111"};
string dd[] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", //2进制转16进制
"a", "b", "c", "d", "e", "f"};
string s1, s2, b1, b2;
string to2 (string s) { //转2进制
string res = "";
for (int i = 0; i < s.size(); i ++) {
if (i == 0) { //防止出现前导0
if (s[i] >= '0' && s[i] <= '9') res += dx[s[i] - '0'];
else res += dx[s[i] - 'a' + 10];
}
else {
if (s[i] >= '0' && s[i] <= '9') res += dy[s[i] - '0'];
else res += dy[s[i] - 'a' + 10];
}
}
return res;
}
string tox(string s) { //转16进制
string res = "";
for (int i = s.size() - 1; i >= 0; i -= 4) {
int start = max(i - 3, 0);
int t = 0;
for (int j = start; j <= i; j ++)
t = t * 2 + s[j] - '0';
res = dd[t] + res;
}
return res;
}
int main() {
int T, tem = 0;
cin >> T;
while (T --) {
s1 = s2 = "";
cin >> s1 >> s2;
b1 = to2(s1), b2 = to2(s2);
int it = 0;
while (it < b1.size() && it < b2.size() && b1[it] == b2[it]) it ++;
string res = b1.substr(0, it);
res = tox(res);
printf("Case #%d: %s\n\n", ++ tem, res.c_str());
}
return 0;
}