p1609_page-0001.jpg

 

考虑最后赢的情况,一定是1和某一个它能打败的队。因此,如果始终保持原始的条件,即1能打败至少一半的队伍,且不能直接打败的队伍都能被间接打败,那么直到最后决赛,2支队伍中必定有一个是1能打败的。则1获得冠军。

构造题

  1. 对于所有1不能打败的队伍,将他们尽可能地与1能打败的队伍配对。因为题目条件,所以最终被配对的能被1打败的队伍一定可以打败所有的不能被1打败的队伍。将选中的能被1打败的队伍留到下一轮,则可以确保不能被1打败的队伍始终可以被间接打败。
  2. 给1随便分配一个未被配对的能被1打败的队伍。
  3. 剩下的不能被1打败的队伍内部打,如果多出来1个,则混入能被1打败的队伍中。
  4. 剩下的能被1打败的队伍,可能还有混进来的那个队,内部打。
  5. 剩下来的队伍晋级下一轮。

本题的关键在于:

  1. 能看出始终保持原始条件则1能夺冠。
  2. 先将两种队伍配对,以确保不能被1打败的队伍始终被间接打败。
  3. 让不能被1打败的队伍内斗,以最安全的方式确保其数量少于总数一半。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 2000;
const int INF = 0x3f3f3f3f;
int n;
char c;
vector<int>win[maxn], die[maxn], ali, ene, tmp;
bool vis[maxn], gg[maxn];
int a[maxn][maxn];
int main() {
while (cin >> n) {
memset(a, 0, sizeof(a));
memset(gg, 0, sizeof(gg));
for (int i = 1; i <= n; i++) {
win[i].clear();
die[i].clear();
}
ali.clear();
ene.clear();
for (int i = 1; i <= n; i++) {
getchar();
for (int j = 1; j <= n; j++) {
scanf("%c", &c);
if (c == '1') {
win[i].push_back(j);
die[j].push_back(i);
a[i][j] = 1;
}
}
}
for (int i : win[1])ali.push_back(i);
for (int i : die[1])ene.push_back(i);
for (int tt = 0; tt < log2(n); tt++) {
memset(vis, 0, sizeof(vis));
tmp.clear();
for (auto it = ene.begin(); it != ene.end(); ) {
int j = 0, p = *it;
for (; j < die[p].size();j++) {
int m = die[p][j];
if ((!vis[m]) && a[1][m] && (!gg[m])) {
printf("%d %d\n", m, p);
vis[m] = 1;
it = ene.erase(it);
break;
}
}
if (j == die[p].size())it++;
}
for (auto it = ali.begin(); it != ali.end(); it++) {
if (!vis[*it]) {
printf("%d %d\n", 1, *it);
gg[*it] = 1;
ali.erase(it);
break;
}
}
bool rest = 0;
if ((ene.size() & 1)) rest = 1;
if (ene.size() > 1) {
int len = ene.size();
for (auto it = ene.begin(); (it + 1) < ene.end();) {
printf("%d %d\n", *it, *(it + 1));
if (a[*it][*(it + 1)]) {
if (it + 2 == ene.end()) {
ene.erase(it + 1);
break;
}
else
it = ene.erase(it + 1);
}
else {
if (it + 2 == ene.end()) {
ene.erase(it);
break;
}
else
it = (ene.erase(it) + 1);
}
}
}
for (int i : ali)if (!vis[i] && !gg[i])tmp.push_back(i);
if (tmp.size() > 1) {
int len = tmp.size();
for (auto it = tmp.begin(); (it + 1) < tmp.end();) {
printf("%d %d\n", *it, *(it + 1));
if (a[*it][*(it + 1)]) {
gg[*(it + 1)] = 1;
if (it + 2 == tmp.end()) {
tmp.erase(it + 1);
break;
}
else
it = tmp.erase(it + 1);
}
else {
gg[*it] = 1;
if (it + 2 == tmp.end()) {
tmp.erase(it);
break;
}
else
it = (tmp.erase(it) + 1);
}
}
}
if (rest) {
printf("%d %d\n", *tmp.rbegin(), *ene.rbegin());
gg[*tmp.rbegin()] = 1;
tmp.erase(--tmp.end());
}
for (int i : ali) {
if (vis[i] && !gg[i])tmp.push_back(i);
}
ali = tmp;
}
}
return 0;
}