姑且把它归类为一道博弈吧,毕竟这也是在找必胜方案。
十分有意思的一道题目,设计一种方案让你支持的1队获胜。
题目给出了两个很重要的条件:
- 1队能打败至少一半的队伍
- 对于1队不能打败的黑队,一定存在一个1队能打败的灰队,使得这支灰队能够打败黑队。也就是说1队可以通过灰队间接打败黑队
一共有2n支队伍,每轮比赛会刷掉一半的队伍,紫书上巧妙的做法就是每轮比赛后让题目给的两个性质依然成立,这样1队最终一定能胜出。
方案如下,大致分为3个阶段:
- 物尽其用。依次考虑每个黑队,如果有能够打败他的灰队的话,便让这两只队伍进行比赛。当然,灰队会晋级下一轮。如果没有能够打败当前黑队而且还没有进行比赛的灰队,那么这支黑队进入后面的混战。
- 让1队胜出。在1队能够打败的队伍中找到一支还未进行比赛的队伍。对于其他未匹配的队伍,也进入下一步的混战。
- 自由混战。黑队和黑队混战,这样能保证至少消灭一半的黑队,顶多有一个黑队剩下。然后剩下的队伍继续混战。
至于为什么这样一定会成功,还请参考紫书。
1 #include <cstdio> 2 #include <vector> 3 using namespace std; 4 5 const int maxn = 1030; 6 7 char table[maxn][maxn]; 8 9 int main() 10 { 11 //freopen("in.txt", "r", stdin); 12 13 int n; 14 while(scanf("%d", &n) == 1 && n) 15 { 16 for(int i = 1; i <= n; i++) scanf("%s", table[i] + 1); 17 vector<int> win, lose; 18 for(int i = 2; i <= n; i++) 19 { 20 if(table[1][i] == '1') win.push_back(i); 21 else lose.push_back(i); 22 } 23 24 int T = n; 25 while(T >>= 1) 26 { 27 vector<int> win2, lose2, final;//进入下一轮1能打败和被打败,以及这一轮混战的队伍 28 bool match; 29 //阶段1:尽可能多的用灰队消灭黑队 30 for(int i = 0; i < lose.size(); i++) 31 { 32 int black = lose[i]; 33 match = false; 34 for(int j = 0; j < win.size(); j++) 35 { 36 int& gray = win[j]; 37 if(gray > 0 && table[gray][black] == '1') 38 { 39 printf("%d %d ", black, gray); 40 match = true; 41 win2.push_back(gray);//灰队进入下一轮 42 gray = 0; 43 break; 44 } 45 } 46 if(!match) final.push_back(black);//进入后面的混战 47 } 48 //阶段2:给1队找个对手 49 match = false; 50 for(int i = 0; i < win.size(); i++) 51 { 52 int team = win[i]; 53 if(team > 0) 54 { 55 if(!match) { printf("1 %d ", team); match = true; } 56 else final.push_back(team);//1已经匹配到对手,该队进入混战 57 } 58 } 59 //阶段3:自由混战,注意到黑队在final中都是挨在一起的 60 for(int i = 0; i < final.size(); i += 2) 61 { 62 printf("%d %d ", final[i], final[i + 1]); 63 int survive = final[i]; 64 if(table[final[i + 1]][final[i]] == '1') survive = final[i + 1]; 65 if(table[1][survive] == '1') win2.push_back(survive); 66 else lose2.push_back(survive); 67 } 68 win = win2; 69 lose = lose2; 70 /*for(int i = 0; i < win.size(); i++) printf("%d ", win[i]); 71 puts(""); 72 for(int i = 0; i < lose.size(); i++) printf("%d ", lose[i]);*/ 73 } 74 } 75 76 return 0; 77 }