1 solutions
-
0
我们对选手的分组情况进行全排列枚举,每一种排列进行模拟,判断 1 号玩家是否为赢家即可。由于全排列当中可能会出现初始分组重复的情况(两个同一组的选手正反顺序算不同排列),枚举之后的答案除以 即可。时间复杂度 。
作为签到题,本题相比往年题目而言,从考察基础的
for
循环改为考察指数型/排列型枚举。对于基础较为薄弱的同学而言会较为棘手。需要注意的是,本题的样例几乎没有任何用处,需要考生对这部分知识点熟练掌握。
全排列的基础写法有两种,基础的深度优先搜索方式可以看这篇题解,这里我们提供一种更简洁的基于 STL 函数
next_permutation
的写法。该函数每次会用 的复杂度给出当前排列按照字典序的下一个排列是什么,因此从字典序最小的排列开始枚举,直至无法循环为止即可。#include <stdio.h> #include <algorithm> int n; int pos[10]; int a[10][10]; int ans; int win[10]; bool judge() { // 初始化:把排列做好 for (int i = 1; i <= n; ++i) win[i] = pos[i]; int tmp_n = n >> 1; while (tmp_n) // 淘汰轮次还在继续 { for (int i = 1; i <= tmp_n; ++i) // 第 i 个赢家从第 i*2-1 个人和第 i*2 个人决出来,不会出现数组被覆盖导致信息错误。 win[i] = a[win[(i << 1) - 1]][win[i << 1]] > 0 ? win[(i << 1) - 1] : win[i << 1]; tmp_n >>= 1; // 每轮淘汰赛完成后,人员减半 } return win[1] == 1; // 赢家是 1 那就是我们要的结果 } int main() { scanf("%d", &n); for (int i = 1; i <= n; ++i) for (int j = 1; j <= n; ++j) scanf("%d", &a[i][j]); for (int i = 1; i <= n; ++i) pos[i] = i; do { ans += judge(); } while (std::next_permutation(pos + 1, pos + n + 1)); // 枚举所有排列 printf("%d", ans >> (n >> 1)); // 除以重复计算的 2^(n/2) 即可,使用位运算即可表示乘除 2 的次幂。 }
- 1
Information
- ID
- 24
- Time
- 1000ms
- Memory
- 512MiB
- Difficulty
- 1
- Tags
- # Submissions
- 8
- Accepted
- 3
- Uploaded By