Dota游戏匹配的所有组合
在Dota游戏中有一种匹配玩法,任意5人以下玩家组队,加入匹配系统,由系统组合出5人 vs 5人的组合进行游戏,比如2人+3人 vs 1人+4人。抽象出这个问题,就变成两边各有m个玩家,最多允许n个人组队(n <= m),计算所有的组合方式。思路是,先考虑单边阵营的组合,比如5人,可以1+4,2+3,1+1+1+1+1...,用递归的方式可以计算出所有的单边阵营组合。将单边阵营的组合两两配对,就获取到双边阵营的组合。假设单边组合有n个,那么双边组合就会有c(n, 2)个。但是这里面会有重复的组合,还得把重复的组合去掉。
void TestLadderRule() { #define OUTPUT_INFO printf("input max camp amount and max team amount(e.g. 5 5): "); OUTPUT_INFO; int nCampMbr = 0; int nMaxTeamMbr = 0; while (scanf_s("%d %d", &nCampMbr, &nMaxTeamMbr) == 2) { LadderRule(nCampMbr, nMaxTeamMbr); OUTPUT_INFO; } } // 参数:阵营人数,最多允许组队人数 void LadderRule( int nCampMbr, int nMaxTeamMbr ) { if (nCampMbr < 1) return; if (nMaxTeamMbr < 0 || nMaxTeamMbr > nCampMbr) return; // 单阵营规则 vector< vector<int> > campRules; // 匹配规则 vector<string> matchRules; // 已经使用过的匹配规则 set<string> usedRules; // 用于生成单阵营规则 int *rule = new int[nCampMbr+1]; memset(rule, 0, sizeof(int)*(nCampMbr+1)); // 找出单边阵营的所有规则 int nTeamMbr = 1; int nSum = 0; bool bUpAmount = false; while (true) { if (!nTeamMbr) break; if (nTeamMbr < nMaxTeamMbr) { if (bUpAmount) { ++rule[nTeamMbr]; nSum += nTeamMbr; bUpAmount = false; } if (nSum > nCampMbr) { nSum -= rule[nTeamMbr] * nTeamMbr; rule[nTeamMbr] = 0; --nTeamMbr; bUpAmount = true; } else { ++nTeamMbr; } } else { if ((nCampMbr - nSum) % nMaxTeamMbr == 0) { rule[nMaxTeamMbr] = (nCampMbr - nSum) / nMaxTeamMbr; vector<int> tempRule; for (int i = 1; i <= nCampMbr; ++i) tempRule.push_back(rule[i]); campRules.push_back(tempRule); } rule[nMaxTeamMbr] = 0; --nTeamMbr; bUpAmount = true; } } // 将单边阵营的规则两两组合,形成匹配规则 for (size_t i = 0; i < campRules.size(); ++i) { for (size_t j = i; j < campRules.size(); ++j) { // 总的规则 char chRule[1025] = { 0 }; char *chPos = chRule; int nLength = 1024; for (int k = 0; k < nCampMbr; ++k) { sprintf_s(chPos, nLength, "%2d ", campRules[i][k] + campRules[j][k]); chPos += 3; nLength -= 3; } // 剔除重复的匹配规则 if (usedRules.count(chRule)) continue; usedRules.insert(chRule); sprintf_s(chPos, nLength, "| "); chPos += 2; nLength -= 2; // 左边阵营规则 for (int k = 0; k < nCampMbr; ++k) { sprintf_s(chPos, nLength, "%2d ", campRules[i][k]); chPos += 3; nLength -= 3; } sprintf_s(chPos, nLength, "| "); chPos += 2; nLength -= 2; // 右边阵营规则 for (int k = 0; k < nCampMbr; ++k) { sprintf_s(chPos, nLength, "%2d ", campRules[j][k]); chPos += 3; nLength -= 3; } matchRules.push_back(chRule); } } sort(matchRules.begin(), matchRules.end()); printf("match rules' amount: %d\n", matchRules.size()); for (auto it = matchRules.begin(); it != matchRules.end(); ++it) { printf("%s\n", it->c_str()); } delete[] rule; }