• 天梯赛 L2-047 锦标赛


    原题链接:

    PTA | 程序设计类实验辅助教学平台

    题面:

    有 2k 名选手将要参加一场锦标赛。锦标赛共有 k 轮,其中第 i 轮的比赛共有 2k−i 场,每场比赛恰有两名选手参加并从中产生一名胜者。每场比赛的安排如下:

    • 对于第 1 轮的第 j 场比赛,由第 (2j−1) 名选手对抗第 2j 名选手。
    • 对于第 i 轮的第 j 场比赛(i>1),由第 (i−1) 轮第 (2j−1) 场比赛的胜者对抗第 (i−1) 轮第 2j 场比赛的胜者。

    第 k 轮唯一一场比赛的胜者就是整个锦标赛的最终胜者。
    举个例子,假如共有 8 名选手参加锦标赛,则比赛的安排如下:

    • 第 1 轮共 4 场比赛:选手 1 vs 选手 2,选手 3 vs 选手 4,选手 5 vs 选手 6,选手 7 vs 选手 8。
    • 第 2 轮共 2 场比赛:第 1 轮第 1 场的胜者 vs 第 1 轮第 2 场的胜者,第 1 轮第 3 场的胜者 vs 第 1 轮第 4 场的胜者。
    • 第 3 轮共 1 场比赛:第 2 轮第 1 场的胜者 vs 第 2 轮第 2 场的胜者。

    已知每一名选手都有一个能力值,其中第 i 名选手的能力值为 ai​。在一场比赛中,若两名选手的能力值不同,则能力值较大的选手一定会打败能力值较小的选手;若两名选手的能力值相同,则两名选手都有可能成为胜者。

    令 li,j​ 表示第 i 轮第 j 场比赛 败者 的能力值,令 w 表示整个锦标赛最终胜者的能力值。给定所有满足 1≤i≤k 且 1≤j≤2k−i 的 li,j​ 以及 w,请还原出 a1​,a2​,⋯,an​。

    输入格式:

    第一行输入一个整数 k(1≤k≤18)表示锦标赛的轮数。
    对于接下来 k 行,第 i 行输入 2k−i 个整数 li,1​,li,2​,⋯,li,2k−i​(1≤li,j​≤109),其中 li,j​ 表示第 i 轮第 j 场比赛 败者 的能力值。
    接下来一行输入一个整数 w(1≤w≤109)表示锦标赛最终胜者的能力值。

    输出格式:

    输出一行 n 个由单个空格分隔的整数 a1​,a2​,⋯,an​,其中 ai​ 表示第 i 名选手的能力值。如果有多种合法答案,请输出任意一种。如果无法还原出能够满足输入数据的答案,输出一行 No Solution
    请勿在行末输出多余空格。

    输入样例1:

    1. 3
    2. 4 5 8 5
    3. 7 6
    4. 8
    5. 9

    输出样例1:

    7 4 8 5 9 8 6 5
    

    输入样例2:

    1. 2
    2. 5 8
    3. 3
    4. 9

    输出样例2:

    No Solution
    

    提示:

    本题返回结果若为格式错误均可视为答案错误

    解题思路:

    本质上是一个灵活使用完全二叉树的题目。

    代码(CPP):

    1. #include
    2. using namespace std;
    3. #define endl '\n'
    4. typedef long long ll;
    5. typedef unsigned long long ull;
    6. const int maxn = 1e3 + 10;
    7. const int INF = 0x3fffffff;
    8. const int mod = 1000000007;
    9. struct node {
    10. int win;
    11. int lose;
    12. } tree[1 << 20];
    13. bool errFlag = false;
    14. void dfs(int root, int size) {
    15. // 递归边界:已经到叶子节点或者此时已经是错误解状态,可以提前返回
    16. if (root * 2 > size || errFlag) {
    17. return;
    18. }
    19. // 得到两个子节点的更强败者以及更弱败者
    20. int bLoser = (tree[root * 2].lose > tree[root * 2 + 1].lose ? root * 2 : root * 2 + 1);
    21. int sLoser = (tree[root * 2].lose < tree[root * 2 + 1].lose ? root * 2 : root * 2 + 1);
    22. // 如果当前的胜者弱于子节点更强的败者,或者当前的败者弱于子节点更弱的败者,则证明这个解是错误的
    23. if (tree[root].win < tree[bLoser].lose || tree[root].lose < tree[sLoser].lose) {
    24. errFlag = true;
    25. return;
    26. }
    27. // 判断
    28. if (tree[bLoser].lose > tree[root].lose) {
    29. // 如果子节点更强的败者强于当前节点的败者,那么当前节点的败者只能是另一个子节点的胜者,此时只有一种解
    30. tree[sLoser].win = tree[root].lose; // 当前的败者一定是从更弱的那边晋级上来的
    31. tree[bLoser].win = tree[root].win; // 当前的胜者一定是从更强的那边晋级上来的
    32. dfs(root * 2, size);
    33. dfs(root * 2 + 1, size);
    34. } else {
    35. // 此时两种解都有可能,都要递归尝试一遍
    36. tree[sLoser].win = tree[root].lose;
    37. tree[bLoser].win = tree[root].win;
    38. dfs(root * 2, size);
    39. dfs(root * 2 + 1, size);
    40. if (errFlag) {
    41. errFlag = false;
    42. swap(tree[sLoser].win, tree[bLoser].win);
    43. dfs(root * 2, size);
    44. dfs(root * 2 + 1, size);
    45. }
    46. }
    47. }
    48. void solve() {
    49. int k;
    50. cin >> k;
    51. int size = (2 << (k - 1)) - 1;
    52. // 输入每一轮每场比赛的败者能力值
    53. for (int i = k; i > 0; i--) {
    54. int n = (1 << (i - 1));
    55. int s = (2 << (i - 1)) - n;
    56. while (n--) {
    57. cin >> tree[s].lose;
    58. s++;
    59. }
    60. }
    61. // 输入最后的冠军能力值,如果冠军能力值低于亚军则证明这是无解的
    62. cin >> tree[1].win;
    63. if (tree[1].lose > tree[1].win) {
    64. errFlag = true;
    65. } else {
    66. dfs(1, size); // 递归填写每一轮每场的胜者能力值
    67. }
    68. // 输出结果
    69. if (errFlag) {
    70. cout << "No Solution\n";
    71. } else {
    72. int n = (1 << (k - 1));
    73. int s = (2 << (k - 1)) - n;
    74. while (n--) {
    75. cout << tree[s].win << " " << tree[s].lose;
    76. s++;
    77. if (n)
    78. cout << " ";
    79. }
    80. }
    81. }
    82. int main() {
    83. // freopen("in.txt", "r", stdin);
    84. ios::sync_with_stdio(false);
    85. cin.tie(0);
    86. cout.tie(0);
    87. cout << fixed;
    88. cout.precision(18);
    89. solve();
    90. return 0;
    91. }

  • 相关阅读:
    防御DDOS的方法是什么?
    漏斗分析模型
    vue2 mixins混入
    [python]pytest运行报错pytest: error: unrecognized arguments: --reruns
    自制操作系统日志——第二十九、三十天
    leetcode:152. 乘积最大子数组
    flink sql clinet 实战:窗口函数----flink-1.13.6
    c语言练习74: 分割数组中数字的数位
    接入API接口文档1688阿里巴巴获取跨境属性数据参考示例
    在灯塔工厂点亮5G,宁德时代抢先探路中国智造
  • 原文地址:https://blog.csdn.net/qq_45554473/article/details/134462864