还记得很久很久以前
我当时还在做《绿色征途》手游版
有一天
计划好友请求同学
先行划桨
吃瓜第一的原则
然后
我看到一堆物理名词
***法律
XXX 公式
呵呵~
我不值得
怪我不努力学习
仔细听
问题原来是
最先抢到的人将从总量中随机选出
稍后抢到的人将从剩余数量中随机选择
所以越早抢红包
金额越大
现在规划希望金额稍微低一些
哦,我惊呼,好人
只是这件事
有必要修复这些吗?
瞬间法则
一会儿公式
他们的最终计划
也很务实
就是大家首先要做出保证。
然后按照之前的红包算法进行分配
嘿
果然,大隐士就躲在城里了
翠花,配牛肉
分析:
解决这个问题的方法有四种(普通法、线段切割法、双随机法、篮球投掷法)。
前三个算法基本都是网上流传的红包手游源码,篮球投篮算法是我自己发明的一个名字。
这个算法还是源于原来的校招,面试北京涂鸦联通,面试官当场引导我一道题,用投篮篮球的例子。 而且当我写这篇博客的时候,我记得这个算法还蛮适用的,所以我把它称为篮球投篮算法。
1.普通法:每次将剩余总量随机化,随机值为第一人的值。 这个算法也是这位朋友之前写的要求优化的算法。 这种算法的优点是完全随机,缺点是很可能前辈抢的太多,后辈抢的太少。 比如100元分给10个人红包手游源码,第一个人会从0到100随机分配,平均值为50。而第二个人剩下的平均值只有25,然后是12.5。
而他们改变的计划大致就是先有保障。 然后随机,一般算法如下:
//普通法 有保底
//iTotalGold总金额 iNum份数 iBaseGold保底金额
void oldThink(int iTotalGold, int iNum, int iBaseGold)
{
if (iBaseGold*iNum > iTotalGold)
{
cout << "保底太多 " << iBaseGold<<endl;
return;
}
iTotalGold -= (iBaseGold *iNum);
std::vector veGold(iNum);
for (int i = 0; i < iNum-1; ++i)
{
int iAddNum = 0;
if(iTotalGold != 0)
iAddNum += rand() % (iTotalGold);
veGold[i] = iAddNum + iBaseGold;
iTotalGold -= iAddNum;
}
veGold[iNum - 1] = iTotalGold + iBaseGold;
cout << "普通法:" << endl;
copy(veGold.begin(), veGold.end(), ostream_iterator(cout, " "));
cout << endl;
}
int main()
{
int iTotalGold = 100;
int iNum = 10;
int iBaseGold = 5;
oldThink(iTotalGold, iNum, iBaseGold);
return 0;
}
2.线段切割法:将总量想象为这么长的线段,需要将其分为num份,随机num-1次,每个随机值映射到线段上。 这样做的用处是给程序赋予随机性,但缺点是有小概率会有人分配过多。 比如100人分享10个红包,我们不仅需要考虑随机值的重合性,而且每次都要完全随机,这可能会导致随机性不足。
//线段切割法 无保底
//iTotalGold总金额 iNum份数 iBaseGold保底金额
void cutline(int iTotalGold, int iNum)
{
if (iNum > iTotalGold)
{
return;
}
if (iNum == iTotalGold)
{
for (int i = 0; i < iNum; ++i)
cout << 1 << " ";
cout << endl;
return;
}
std::set setGold;
for (int i = 0; i < iNum-1; ++i)
{
while (1)
{
int iPos = rand() % iTotalGold;
if (setGold.find(iPos) == setGold.end())
{
setGold.insert(iPos);
break;
}
}
}
cout << "线段切割法(无保底):" << endl;
int iPreLine = 0;
for (auto &it : setGold)
{
cout << it - iPreLine << " ";
iPreLine = it;
}
cout << iTotalGold - iPreLine << " ";
cout << endl;
}
int main()
{
int iTotalGold = 100;
int iNum = 10;
int iBaseGold = 5;
cutline(iTotalGold, iNum);
return 0;
}
这个算法已经比第一个算法更好了。 如果你觉得随机性太强,你可以为这些算法做一个保证策略。 可以预见,效果一定比第一个更好。
3、双倍随机法:每次随机,取每人平均金额的0-2倍进行随机。 这已经基本上达到了我们想要的效果,很好。 比如:100人分为10个点,每次随机都是0-100/10*2来随机化,基本可以保证每个人平均在10个左右,是一个相当平均的算法。 不过需要注意的是,最后的几个人可能还不到20人。
//双倍随机法
//iTotalGold总金额 iNum份数 iBaseGold保底金额
void twobase(int iTotalGold, int iNum, int iBaseGold)
{
if (iNum *iBaseGold > iTotalGold)
{
cout << "保底太多 " << iBaseGold << endl;
return;
}
std::vector veGold(iNum, iBaseGold);
iTotalGold -= iNum*iBaseGold;
int iBaseTmp = iTotalGold / iNum * 2;
for (int i = 0; i = iBaseTmp)
iTmp = rand() % iBaseTmp;
else
iTmp = rand() % iTotalGold;
veGold[i] += iTmp;
iTotalGold -= iTmp;
}
veGold[iNum - 1] = iTotalGold;
cout << "双倍随机法:" << endl;
copy(veGold.begin(), veGold.end(), ostream_iterator(cout, " "));
cout << endl;
}
int main()
{
int iTotalGold = 100;
int iNum = 10;
int iBaseGold = 5;
twobase(iTotalGold, iNum, iBaseGold);
return 0;
}
从疗效可以看出,这种随机方法取得了非常好的随机疗效。 玩家投诉几乎杜绝。
4.我自创的名字,篮球投篮方法:之前我都是用金额消除人数num来求平均值。 篮球的投篮方式是按照投篮金额的单位价值来计算的。 以上三种算法都是尽量寻求随机性,而篮球投篮规则是保证完全平均。 例如:100人分为10分,每次取金额的最小单位值,比如1块钱,然后10个人当一个篮子,1块钱当一个足球,球每次都通过。 这样做的好处是不需要模仿完全随机,本身就是完全随机的,缺点也很明显,循环太多。
针对他循环太多的缺点,我自己做了一层优化。 使用最小数量的单位值,例如每次取三块或五块。 这种优化可以避免过多的循环。 其次,它还可以防止极端情况下结果过于随机。
//投篮球法 有保底
//iTotalGold总金额 iNum份数 iBaseGold保底金额
void basketball(int iTotalGold, int iNum, int iBaseGold)
{
if (iBaseGold*iNum > iTotalGold)
{
cout << "保底太多 " << iBaseGold << endl;
return;
}
iTotalGold -= (iBaseGold *iNum);
std::vector veGold(iNum, iBaseGold);
for (int i = 0; i < iTotalGold; i += 2) //这里基准值用了2,减少循环次数
{
int iPos = rand() % iNum;
veGold[iPos] += 2;
}
cout << "投篮球法:" << endl;
copy(veGold.begin(), veGold.end(), ostream_iterator(cout, " "));
cout << endl;
}
int main()
{
int iTotalGold = 100;
int iNum = 10;
int iBaseGold = 5;
basketball(iTotalGold, iNum, iBaseGold);
return 0;
}
闲人避免
我要假装
从物理理论的角度来看,只要随机数足够大,结果必然无限接近平衡。 因此,虽然这些算法的循环次数过多,但当数据量足够大时,它们必须是最优的、平衡的。
当然,算法是服务于功能的,上面的推论是有限的,规划者希望你得到的都是类似的。
最后,将四种算法一起运行来比较结果。
上图中还有一个小点,运行程序两次得到的结果是一模一样的。 这是因为旧版本C++中rand函数的随机因子是一个定值问题。 关于随机因素和随机数,改天有时间我会整理一篇文章来描述。
在这里,我们首先解决这些情况。 只需要在程序每次运行时重新指定随机因子即可。 例如:srand((无符号)时间(0));
运行结果:
源代码:
#include
#include
#include
#include
#include
#include
using namespace std;
//普通法 有保底
//iTotalGold总金额 iNum份数 iBaseGold保底金额
void oldThink(int iTotalGold, int iNum, int iBaseGold)
{
if (iBaseGold*iNum > iTotalGold)
{
cout << "保底太多 " << iBaseGold<<endl;
return;
}
iTotalGold -= (iBaseGold *iNum);
std::vector veGold(iNum);
for (int i = 0; i < iNum-1; ++i)
{
int iAddNum = 0;
if(iTotalGold != 0)
iAddNum += rand() % (iTotalGold);
veGold[i] = iAddNum + iBaseGold;
iTotalGold -= iAddNum;
}
veGold[iNum - 1] = iTotalGold + iBaseGold;
cout << "普通法:" << endl;
copy(veGold.begin(), veGold.end(), ostream_iterator(cout, " "));
cout < iTotalGold)
{
return;
}
if (iNum == iTotalGold)
{
for (int i = 0; i < iNum; ++i)
cout << 1 << " ";
cout << endl;
return;
}
std::set setGold;
for (int i = 0; i < iNum-1; ++i)
{
while (1)
{
int iPos = rand() % iTotalGold;
if (setGold.find(iPos) == setGold.end())
{
setGold.insert(iPos);
break;
}
}
}
cout << "线段切割法(无保底):" << endl;
int iPreLine = 0;
for (std::set::iterator it = setGold.begin(); it != setGold.end(); ++it)
{
cout << *it - iPreLine << " ";
iPreLine = *it;
}
cout << iTotalGold - iPreLine << " ";
cout < iTotalGold)
{
cout << "保底太多 " << iBaseGold << endl;
return;
}
std::vector veGold(iNum, iBaseGold);
iTotalGold -= iNum*iBaseGold;
int iBaseTmp = iTotalGold / iNum * 2;
for (int i = 0; i = iBaseTmp)
iTmp = rand() % iBaseTmp;
else
iTmp = rand() % iTotalGold;
veGold[i] += iTmp;
iTotalGold -= iTmp;
}
veGold[iNum - 1] = iTotalGold;
cout << "双倍随机法:" << endl;
copy(veGold.begin(), veGold.end(), ostream_iterator(cout, " "));
cout < iTotalGold)
{
cout << "保底太多 " << iBaseGold << endl;
return;
}
iTotalGold -= (iBaseGold *iNum);
std::vector veGold(iNum, iBaseGold);
for (int i = 0; i < iTotalGold; i += 2) //这里基准值用了2,减少循环次数
{
int iPos = rand() % iNum;
veGold[iPos] += 2;
}
cout << "投篮球法:" << endl;
copy(veGold.begin(), veGold.end(), ostream_iterator(cout, " "));
cout << endl;
}
int main()
{
srand((unsigned)time(0));
int iTotalGold = 100;
int iNum = 10;
int iBaseGold = 5;
oldThink(iTotalGold, iNum, iBaseGold);
cutline(iTotalGold, iNum);
twobase(iTotalGold, iNum, iBaseGold);
basketball(iTotalGold, iNum, iBaseGold);
return 0;
}
建立手游平台源码,首先要了解手游平台源码是什么。 源代码是编程软件最原始的代码。 它是一种编程语言。 如果您不知道代码是什么,可以在浏览器中打开网页,然后按 F12 键。 您可以查看该页面的源代码。 源代码只有用专门的软件编译后才能运行。 可以直接更改游戏中的源代码来改变游戏类型的布局。 关于ios手游公益游戏公益相关信息,从专业的角度为您解答相关问题,为您提供优质的服务!
游戏建设
游戏源码系统平台有网站源码,可以优化网站、布局、界面等。提供100%本地系统娱乐开源游戏联运平台,方便二次开发,集成全套系统开发游戏官方网站、系统后台、渠道SKD等
源代码的好处:
1.它们会增加企业部署网络和各种服务的成本。 如果使用开源方案,只需要一台服务器,其他的可以免费使用windows,操作系统则要付费(假设没有盗版)。
2、二次开发可以在源代码的基础上建立或丰富现有的系统功能。
3.参考研究。 通过剖析源码,我们可以学习开发,了解开发者的视角,了解开发者如何聪明地解决业务问题。 阅读源代码是提高开发技能的捷径。
4、拥有源代码可以抢占先机。 如果开发商的报价远远超过市场价格用于后期运维或减少功能,而客户有源代码手游源码合集,则可以考虑更换开发商,而不是重新绘制整个软件。
因为每个业务、每个客户的需求可能不同,所以可以选择有源代码的公司。 您可以自由修改源代码并进行二次开发。 如何订购OEM平台? 如果难以获取源代码,就很难进行二次开发。 限制太多了。 为此手游源码合集,订阅源系统并自己控制它是最好的新交易。
选择一个可靠的手机游戏平台非常重要。 一个好的起点,可以决定你少走多少弯路,你就能快速开始赚钱。 小型手游平台是菜鸟游戏代理商的首选。 可为新手游戏代理商提供一对一的客服指导和咨询。 源代码开源,源代码开源支持二次开发。 游戏的选择将变得更加严格和精准,新手游戏代理商可以快速找到好的推广游戏。
手机游戏代理作为一种新兴的创业项目,随着游戏的流行而诞生。 可以说,只要游戏三天不涨,手游机构的收入就持续可观。 手游代理行业的发展尚未达到顶峰,仍有进一步发展的空间。
从近几年的趋势来看,手机游戏行业已经成为很多人的选择。 事实上,很多人对手游创业了解不够。 手游创业的范围比较广,但就目前热门的手游创业项目而言,我们可以采用手游代理作为手游创业的一种形式。 顾名思义,手游代理就是代理游戏,然后运营推广,最终获得收益分成。