N進制算法的數學邏輯抽象及擴展

N進制問題其實可以理解爲有一定數量的金幣(X個)放在N+1個柱子上的問題。有很多應用場景。

至少目前遇見的有兩處:

第一:遊戲中玩家數據統計時,有很多維度,如等級、VIP等級、是否參與某活動、在此活動中升到的等級等等。之前項目中有五個維度,示例代碼:

 

class DataSortKey
{
public:
    DataSortKey(){ memset(this, 0, sizeof(*this)); }
    unsigned level;
    unsigned vip_level;
    unsigned param1;
    uint64_t param2;
    unsigned param3;
};

bool operator<(const DataSortKey& lhs, const DataSortKey& rhs);

第二:在N個數中取0~X個(0<X<N)之和,設一定的上限,可以重複取,求可以取到的所有組合。示例代碼:

 

 

class CoinOnColumn
{
public:
	CoinOnColumn(int coin_count, int column_count)
	{
		this->coin_count = coin_count;
		// 加上了一個空柱子 0-column_count其實是column_count+1個柱子
		this->column_count = column_count;
		coin_column_idxs.resize(coin_count, 0);
	}
	void Add()
	{
		////已是最大
		//if (IsMax())
		//{
		//	return;
		//}

		for (int nIdx = 0; nIdx < coin_count; ++nIdx)
		{
			if (coin_column_idxs[nIdx] == column_count)
			{
				continue;
			}
			else
			{
				++coin_column_idxs[nIdx];
				for (int j = 0; j < nIdx; ++j)
				{
					coin_column_idxs[j] = 0;
				}
				return;
			}
		}

		++coin_column_idxs[coin_count - 1];
		for (int j = 0; j < coin_count - 1; ++j)
		{
			coin_column_idxs[j] = 0;
		}
	}
	std::vector<int> coin_column_idxs;
	// 硬幣數量
	int coin_count;
	// 柱子數量,包括添加的0號柱子,硬幣在0號柱子上表示不算
	int column_count;
	bool IsMax()
	{
		for (int nIdx = 0; nIdx < coin_count; ++nIdx)
		{
			if (coin_column_idxs[nIdx] != column_count)
			{
				return false;
			}
		}
		return true;
	}
};

使用:

 

 

void GetNumber2(int data[], int nDataCount, int nElementMax, int nElementCount, std::vector<int>& vecRet)
{
	CoinOnColumn coc(nElementCount, nDataCount);
	while (!coc.IsMax())
	{
		coc.Add();
		int result = 0;
		for (int nIdx = 0; nIdx < nElementCount && result <= nElementMax; ++nIdx)
		{
			//金幣在0號柱子上表示沒有意義,不用加
			if (coc.coin_column_idxs[nIdx] > 0)
			{
				result += data[coc.coin_column_idxs[nIdx] - 1];
			}
		}
		if (result <= nElementMax)
		{
			vecRet[result] = 1;
		}
	}

}

main中使用:

 

 

	int data[17] ={ 3, 4, 5, 10, 15, 20, 25, 30, 40, 50, 60, 75, 80, 100, 150, 200, 250};
	int data_size = sizeof(data) / sizeof(data[0]);

	ofstream ofs("numbers.txt", std::ios::app);
	for (int i = 1; i < 10; ++i)
	{
		std::vector<int> vecRet;
		vecRet.resize(250 + 1);
		GetNumber2(data, data_size, 250, i, vecRet);
		//std::sort(vecRet.begin(), vecRet.end());
		for (int nIdx = 1; nIdx < vecRet.size(); ++nIdx)
		{
			if (vecRet[nIdx] == 1)
			{
				ofs << nIdx << " ";
			}
		}
		ofs << endl;
	}
	ofs.flush();
	ofs.close();

其邏輯抽象其實就是一個N進制的問題。這裏簡記一下,備忘。
注意這裏第二個問題是第一個問題的特化。第一個問題中,每個數據的維度可以分別有一個上限,也可以分別有一個起始值,還可以分別有一個步長。比如“統計所有玩家在等級/VIP等級上的分佈,每5級一檔,每2個VIP等級一檔”,這時候等級被劃定爲1-5/6-10/11-15/16-20......VIP等級被劃定爲0-1/2-3/4-5/6-7,等級起始值爲1,終止值爲最高等級(比如100級就是100),步長爲5。VIP起始值爲0,終止值爲VIP最高等級(如15),步長爲2。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章