链接:
https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4484
题意:
n支队伍(2≤n≤1024,且n是2的整数幂)打淘汰赛,每轮都是两两配对,胜者进入下一轮。
每支队伍的实力固定,并且已知每两支队伍之间的一场比赛结果(“实力固定”是指,例如,
队伍1曾经胜过队伍2,则二者在今后的交锋中队伍1总会获胜)。你喜欢1号队。虽然
它不一定是最强的,但是它可以直接打败其他队伍中的至少一半,并且对于每支1号队不能
直接打败的队伍t,总是存在一支1号队能直接打败的队伍t'使得t'能直接打败t。
问:如何安排比赛,使得1号队夺冠?
分析:
构造法。
用黑色代表强队(即1号队不能直接打败的队伍),再用灰色代表“有用的队”,
即能打败某个黑色队但不能打败1号队的队伍(说它们有用是因为可以间接打败黑色队)。
将每一轮比赛分为四个阶段,直到第logn轮:
阶段1:尽量“消灭”黑色队,即依次考虑每一个黑色队,选一个能打败且还没安排对手的灰色队。
阶段2:给1号队任选一个能打败的。这个选择一定可以成功,因为1号队能打败的队伍至少一半(题设)。
阶段3:把剩下的黑色队伍任意配对,任它们“自相残杀”,不管谁赢都无所谓。
阶段4:剩下的队伍任意配对。
代码:
1 #include <cstdio> 2 #include <vector> 3 using namespace std; 4 5 const int UP = 1024 + 5; 6 char res[UP][UP]; 7 8 int main(){ 9 int n; 10 while(~scanf("%d", &n)){ 11 for(int i = 1; i <= n; i++) scanf("%s", res[i] + 1); 12 13 vector<int> win, lose; 14 for(int i = 2; i <= n; i++){ 15 if(res[1][i] == '1') win.push_back(i); 16 else lose.push_back(i); 17 } 18 19 while(n > 1){ 20 vector<int> win2, lose2, last; 21 22 for(int i = 0; i < lose.size(); i++){ 23 int lid = lose[i]; 24 bool found = false; 25 for(int t = 0; t < win.size(); t++){ 26 int& wid = win[t]; 27 if(wid && res[wid][lid] == '1'){ 28 printf("%d %d ", wid, lid); 29 win2.push_back(wid); 30 wid = 0; 31 found = true; 32 break; 33 } 34 } 35 if(!found) last.push_back(lid); 36 } 37 38 bool first = true; 39 for(int i = 0; i < win.size(); i++){ 40 int wid = win[i]; 41 if(wid){ 42 if(first) printf("1 %d ", wid), first = false; 43 else last.push_back(wid); 44 } 45 } 46 47 for(int i = 0; i < last.size(); i += 2){ 48 printf("%d %d ", last[i], last[i+1]); 49 int wid = last[i+1]; 50 if(res[last[i]][wid] == '1') wid = last[i]; 51 if(res[1][wid] == '1') win2.push_back(wid); 52 else lose2.push_back(wid); 53 } 54 55 win = win2; 56 lose = lose2; 57 n >>= 1; 58 } 59 } 60 return 0; 61 }