微信红包算法,拆分最大的红包法

我的算法是,通过不断拆分最大的红包,完成所有红包金额的分配。

先把总金额存入红包列表中,然后开始。

第一步:从列表中找出已分配的红包中最大的红包金额,通过随机数将这个红包金额拆分成两个金额,然后保存在红包列表中。

第二步:继续第一步,直到红包拆分完毕。

为了方便运算,金额统一转换为分,输出结果时再转换回元和分。

头文件:

#pragma once

const unsigned int g_unMaxMoney = 10000 * 100;	// 最大允许发10000元红包


class CSendRadPacket
{
public:
	CSendRadPacket();
	~CSendRadPacket();

	bool CalRadPacket(unsigned int unYuan, unsigned int unFen, unsigned int unCount);

	void PrintRadPacket();

protected:
	unsigned int GetMaxNum();

	void SaveMoney(unsigned int unNum);

protected:
	unsigned int *m_pPackeData;		// 保存计算好的每一个红包金额
	unsigned int m_unPacketCount;	// 红包数量
	unsigned int m_unAllMoney;		// 红包总金额
};

cpp代码:

#include "stdafx.h"
#include "CSendRadPacket.h"
#include <iostream>
#include <iomanip>

using namespace std;


CSendRadPacket::CSendRadPacket() :
	m_pPackeData(nullptr),
	m_unPacketCount(0),
	m_unAllMoney(0)
{
}

CSendRadPacket::~CSendRadPacket()
{
	if (nullptr == m_pPackeData)
	{
		delete[] m_pPackeData;
		m_pPackeData = nullptr;
	}
}

bool CSendRadPacket::CalRadPacket(unsigned int unYuan, unsigned int unFen, unsigned int unCount)
{
	// 先把总金额转换成分。红包数量少于1,返回;总金额数小于红包数,返回;超过最大红包值,返回。
	unsigned int unMoney = unYuan * 100 + unFen;
	bool bRes = ((unCount < 1) || (unMoney < unCount) || (unMoney > g_unMaxMoney) || (unFen > 99));
	if (bRes)
	{
		return false;
	}

	if (nullptr != m_pPackeData)
	{
		delete[] m_pPackeData;
		m_pPackeData = nullptr;
	}

	m_pPackeData = new unsigned int[unCount];
	if (nullptr == m_pPackeData)
	{
		return false;
	}
	memset(m_pPackeData, 0, sizeof(int) * unCount);
	m_pPackeData[0] = unMoney;
	m_unPacketCount = unCount;
	m_unAllMoney = unMoney;

	for (unsigned int unIndex = 0; unIndex < unCount - 1; ++unIndex)
	{
		unsigned int unMaxMoney = GetMaxNum();

		unsigned int nRandom = ((rand() + rand()) << 16) + rand() + rand();
		unsigned int unLeft = nRandom % unMaxMoney;	// 有余数为0的可能
		unsigned int unRight = unMaxMoney - unLeft;

		// 如果遇到 nLeft 或 nRight 有一个为0的情况,需要再分配一次
		if (0 == unLeft || 0 == unRight)
		{
			--unIndex;
		}

		//如果遇到 nLeft 或 nRight 有一个为0的情况,还需要将 nLeft 或 nRight 重新存一遍。
		// 因为 GetMaxNum() 函数取出最大值后,会将列表中的最大值置为0
		SaveMoney(unLeft);
		SaveMoney(unRight);
	}

	return true;
}

void CSendRadPacket::PrintRadPacket()
{
	if (m_unPacketCount < 1)
	{
		return;
	}

	cout << endl;
	cout << "红包总金额:" << m_unAllMoney / 100 << "." << setfill('0') << setw(2) << m_unAllMoney % 100 << endl;
	cout << "红包个数:" << m_unPacketCount << endl;
	unsigned int unMaxMoney = 0;
	unsigned int unMinMoney = -1;
	for (unsigned int unIndex = 0; unIndex < m_unPacketCount; ++unIndex)
	{
		unsigned int unNum = m_pPackeData[unIndex];
		cout << unNum / 100 << "." << setfill('0') << setw(2) << unNum % 100 << "  ";

		if (unNum > unMaxMoney)
		{
			unMaxMoney = unNum;
		}
		if (unNum < unMinMoney)
		{
			unMinMoney = unNum;
		}
	}
	cout << endl;
	cout << "最大的红包是:" << unMaxMoney / 100 << "." << setfill('0') << setw(2) << unMaxMoney % 100 << "  " << endl;
	cout << "最小的红包是:" << unMinMoney / 100 << "." << setfill('0') << setw(2) << unMinMoney % 100 << "  " << endl;
}

unsigned int CSendRadPacket::GetMaxNum()
{
	unsigned int unMaxIndex = 0;
	for (unsigned int unIndex = 1; unIndex < m_unPacketCount; ++unIndex)
	{
		if (m_pPackeData[unIndex] > m_pPackeData[unMaxIndex])
		{
			unMaxIndex = unIndex;
		}
		if (0 == m_pPackeData[unIndex])
		{
			break;
		}
	}
	unsigned int unMaxNum = m_pPackeData[unMaxIndex];
	m_pPackeData[unMaxIndex] = 0;

	return unMaxNum;
}

void CSendRadPacket::SaveMoney(unsigned int unNum)
{
	for (unsigned int unIndex = 0; unIndex < m_unPacketCount; ++unIndex)
	{
		if (0 == m_pPackeData[unIndex])
		{
			m_pPackeData[unIndex] = unNum;
			break;
		}
	}
}

主函数:

void main()
{
	unique_ptr<CSendRadPacket> oPacket(new CSendRadPacket);
	oPacket->CalRadPacket(0, 99, 1);
	oPacket->PrintRadPacket();
	oPacket->CalRadPacket(1, 0, 2);
	oPacket->PrintRadPacket();
	oPacket->CalRadPacket(0, 5, 5);
	oPacket->PrintRadPacket();
	oPacket->CalRadPacket(0, 8, 7);
	oPacket->PrintRadPacket();
	oPacket->CalRadPacket(1, 0, 7);
	oPacket->PrintRadPacket();
	oPacket->CalRadPacket(5, 20, 7);
	oPacket->PrintRadPacket();
	oPacket->CalRadPacket(10, 0, 10);
	oPacket->PrintRadPacket();
	oPacket->CalRadPacket(520, 0, 10);
	oPacket->PrintRadPacket();
	oPacket->CalRadPacket(1000, 0, 10);
	oPacket->PrintRadPacket();
	oPacket->CalRadPacket(8888, 88, 9);
	oPacket->PrintRadPacket();
}

执行结果:



从多次运行的结果来看,红包金额分布的状况和微信红包差不多。并且从我的算法来看,不存在第几个红包为最大红包的概率最大。

猜你喜欢

转载自blog.csdn.net/jbz001/article/details/80297057