题目分析
综合题意,将最后一场比赛视为顶层,第一轮比赛视为第一层,则有:
下层每场比赛选出一个胜者,每两个下层的胜者间举行本层的一次比赛,显然这是一个二叉树。考虑还原建立每场比赛的树。
由于最后一层的比赛是$2^k$个选手参加,故这是个完美二叉树,使用完全二叉树的数组储存方式,则标号为$n$的节点的左孩子标号:$n<<1$,右孩子为$n<<1|1$[1]
对于一场比赛的两位参与者,其分别是这场比赛的左孩子比赛的胜者和右孩子比赛的胜者。
故进行暴力穷举,对于两位参与者ab来说,先考虑a来自左孩子。若不合理,再考虑a来自右孩子。
个人示例代码
#include <iostream>
using namespace std;
typedef long long ll;
// 16min,进步!
const int N = 1 << 19;
struct node
{
int win;
int lose;
} tree[N];
// 前k层: 2^k-1
int k;
bool solve(int n) // 还原n号节点的子节点,并检查自身合理性
{
if (n >= 1 << k)
return true;
else if (tree[n].lose > tree[n].win)
return false;
tree[n << 1].win = tree[n].win;
tree[n << 1 | 1].win = tree[n].lose;
if (solve(n << 1) && solve(n << 1 | 1))
return true;
swap(tree[n << 1].win, tree[n << 1 | 1].win);
if (solve(n << 1) && solve(n << 1 | 1))
return true;
return false;
}
int main()
{
cin >> k;
for (int i = k; i >= 1; i--)
for (int j = 1 << (i - 1); j < 1 << i; j++)
cin >> tree[j].lose;
cin >> tree[1].win;
if (solve(1))
for (int j = 1 << k - 1; j < 1 << k; j++)
cout << tree[j].win << ' ' << tree[j].lose << " \n"[j == (1 << k) - 1];
else
cout << "No Solution" << endl;
return 0;
}
位运算中,$n<<1$ 相当于 $n\times2$, $n<<1$作为一个二进制末尾为0的数,$n<<1|1=n \times 2+1$ ↩︎