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;
}

代码: https://github.com/windpenguin/WindUtilities

猜你喜欢

转载自blog.csdn.net/windpenguin/article/details/62238052