我的算法是,通过不断拆分最大的红包,完成所有红包金额的分配。
先把总金额存入红包列表中,然后开始。
第一步:从列表中找出已分配的红包中最大的红包金额,通过随机数将这个红包金额拆分成两个金额,然后保存在红包列表中。
第二步:继续第一步,直到红包拆分完毕。
为了方便运算,金额统一转换为分,输出结果时再转换回元和分。
头文件:
#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(); }
执行结果:
从多次运行的结果来看,红包金额分布的状况和微信红包差不多。并且从我的算法来看,不存在第几个红包为最大红包的概率最大。