#include <stdio.h>
#include <stdlib.h>
#include <time.h>
//#define demo // 范例程序,此范例程序没有考虑公平性,总金额方差巨大,仅供主框架调试,请写出自己的抢红包算法
// 函数功能 : 生成切割点(需要生成人数减1个切割点)
// 输入 : amount : 总金额 (单位: 分)
// : peoples : 总人数
// 输出 : cut_point : 切割点
static void Make_Cut_Point(int *cut_point, int amount, int peoples)
{
char repeat_flag; //重复切割点标志位,1:生成了重复切割点;0:不重复
int i, j;
for (i = 0; i < (peoples - 1); i++) {
do {
repeat_flag = 0;
cut_point[i] = rand() % amount;
if (cut_point[i] == 0) { //至少要有1分钱
cut_point[i] = 1;
} else if (cut_point[i] == amount) { //要给最后一个人留一分钱
cut_point[i] = amount - 1;
}
for (j = 0; j < i; j++) {
if (cut_point[i] == cut_point[j]) { //若切割点已生成,则重新生成
repeat_flag = 1;
break;
}
}
} while(repeat_flag);
}
}
// 函数功能 : 对切割点进行排序(从小到大排)
// 输入 : num : 切割点数
// 输出 : cut_point : 从小到大排列的切割点
static void Sort_Cut_Point(int *cut_point, int num)
{
int temp;
int i, j;
for (i = 0; i < num; i++) {
for (j = i + 1; j < num; j++) {
if (cut_point[i] > cut_point[j]) {
temp = cut_point[i];
cut_point[i] = cut_point[j];
cut_point[j] = temp;
}
}
}
}
// 函数功能 : 生成红包
// 输入 : amount : 总金额 (单位: 分)
// : peoples : 总人数
// 输出 : money : 红包
static void Make_Red_Package(int *money, int amount, int peoples)
{
#ifdef demo
int i;
for (i = 0 ; i < (peoples - 1) ; i++) {
money[i] = rand() % amount;
amount -= money[i];
}
money[i] = amount;
#endif
int *cut_point; // 记录切割点
int i;
cut_point = (int *)malloc((peoples - 1) * sizeof(int));
/* 1.生成切割点 */
Make_Cut_Point(cut_point, amount, peoples);
/*
for (i = 0; i < (peoples - 1); i++) {
printf("a[%d] %d\n", i, cut_point[i]);
}*/
/* 2.将切割点按从小到大进行排序 */
Sort_Cut_Point(cut_point, (peoples - 1));
/*
for (i = 0; i < (peoples - 1); i++) {
printf("b[%d] %d\n", i, cut_point[i]);
}*/
/* 3.分红包,按切割的段数分 */
for (i = 0; i < peoples; i++) {
if (i == 0) {
money[i] = cut_point[i];
} else if (i == (peoples - 1)) {
money[i] = amount - cut_point[peoples - 2];
} else {
money[i] = cut_point[i] - cut_point[i - 1];
}
}
}
/******* 请在这里描述你的算法 *************************************************
算法描述:
将红包总金额视为一段长度,从中随机取(人数减1)个切割点将线段切割为(等同人数)的份数然后分配
******************************************************************************/
// ---------------- 上面的函数为抢红包算法,不要修改函数接口,函数体内部的程序请自己实现 --------------------
// ---------------- 下面的代码为抢红包算法调试框架 ----------------------------------------------------------
// 函数功能 : 累加每个人的总收入
// 输入 : peoples : 总人数
// : money : 本次每个人抢到的红包金额
// 输出 : total : 每个人累计抢到的红包金额
static void cal_total_money(int *total, int peoples, int const *money)
{
int i;
for (i = 0 ; i < peoples ; i++) {
total[i] += money[i]; // 累加上本次抢到的红包金额
}
}
// 函数功能 : 查找人气王
// 输入 : peoples : 总人数
// : money : 每个人抢到的红包金额
// 返回 : 人气王编号
static int Find_lucky_king(int peoples, int const *money)
{
int i, max_money, max_idx;
max_idx = 0; // 先假设第一个人是人气王
max_money = money[max_idx]; // 记录人气王抢到的钱
for (i = 1 ; i < peoples ; i++) { // 从第二个人开始比较
if (money[i] > max_money) { // 发现抢到更多钱的人
max_idx = i; // 变更人气王编号
max_money = money[max_idx]; // 记录人气王抢到的钱
}
}
return max_idx; // 返回人气王编号
}
// 函数功能 : 查找衰神
// 输入 : peoples : 总人数
// : money : 每个人抢到的红包金额
// 返回 : 衰神编号
static int Find_Decadence(int peoples, int const *money)
{
int i, min_money, min_idx;
min_idx = 0; // 先假设第一个人是衰神
min_money = money[min_idx]; // 记录衰神抢到的钱
for (i = 1 ; i < peoples ; i++) { // 从第二个人开始比较
if (money[i] < min_money) { // 发现抢到更少钱的人
min_idx = i; // 变更衰神编号
min_money = money[min_idx]; // 记录衰神抢到的钱
}
}
return min_idx; // 返回衰神编号
}
// 函数功能 : 更新每个人曾经获取的最大红包
// 输入 : peoples : 总人数
// : money : 每个人抢到的红包金额
// 输出 : max_money : 每个人历史上抢到的最大红包值
static void Change_Max_Package(int *max_money, int peoples, int const *money)
{
int i;
for (i = 0 ; i < peoples ; i++) {
if (money[i] > max_money[i]) { // 本次抢到的红包大于历史上的最大红包
max_money[i] = money[i]; // 更新历史最大红包
}
}
}
// 函数功能 : 更新每个人曾经获取的最小红包
// 输入 : peoples : 总人数
// : money : 每个人抢到的红包金额
// 输出 : min_money : 每个人历史上抢到的最小红包值
static void Change_Min_Package(int *min_money, int peoples, int const *money)
{
int i;
for (i = 0 ; i < peoples ; i++) {
if (money[i] < min_money[i]) { // 本次抢到的红包小于历史上的最小红包
min_money[i] = money[i]; // 更新历史最小红包
}
}
}
// 函数功能 : 计算方差
// 输入 : count : 总人数
// : val_list : 每个人的总金额
// : div : 用于把单位转换成元
// 返回 : 方差
static double Cal_variance(int count, int const *val_list, int div)
{
double variance, average_total;
int i;
variance = 0;
average_total = 0;
for (i = 0; i < count; i++) {
average_total += val_list[i]; // 计算累加和
}
average_total /= count; // 计算平均值
for (i = 0; i < count; i++) {
double temp; // 用于计算当前值 和 平均值 的差值 的绝对值
if (val_list[i] > average_total) {
temp = val_list[i] - average_total;
} else {
temp = average_total - val_list[i];
}
temp /= div; // 把单位转换为元
variance += temp * temp;
}
variance /= count;
return variance;
}
#define CENT_PER_YUAN 100 // 1元 == 100分
// 函数功能 : 发n次红包
// 输入 : amount : 发一次红包的金额
// peoples : 参与发红包的人数
// times : 发红包次数
static void Red_Packet_nTimes(int amount, int peoples, int times)
{
int i;
int *money; // 抢一次红包的金额
int *total_money; // 抢n次红包的总金额
int *lucky_king; // 幸运王次数
int *Decadence; // 衰神次数
int *max_money; // n次抢红包中,抢到的最大值
int *min_money; // n次抢红包中,抢到的最小值
if ((amount < peoples) || (peoples < 1) || (times < 1)) { // 检查输入参数合法性
printf("input error\r\n");
return;
}
srand((unsigned)time(NULL)); // 初始化随机数发生器
money = (int *)malloc(peoples * sizeof(int));
total_money = (int *)malloc(peoples * sizeof(int));
lucky_king = (int *)malloc(peoples * sizeof(int));
Decadence = (int *)malloc(peoples * sizeof(int));
max_money = (int *)malloc(peoples * sizeof(int));
min_money = (int *)malloc(peoples * sizeof(int));
for (i = 0; i < times; i++) {
Make_Red_Package(money, amount, peoples); // 生成单次红包
if (i == 0) { // 第一次抢红包初始化一些参数
int j;
for (j = 0 ; j < peoples ; j++) {
total_money[j] = 0;
lucky_king[j] = 0;
Decadence[j] = 0;
max_money[j] = money[j];
min_money[j] = money[j];
}
}
cal_total_money(total_money, peoples, money); // 累计每个人的总收入
lucky_king[Find_lucky_king(peoples, money)]++; // 人气王次数加1
Decadence[Find_Decadence(peoples, money)]++; // 衰神次数加1
Change_Max_Package(max_money, peoples, money); // 更新每个人曾经获取的最大红包
Change_Min_Package(min_money, peoples, money); // 更新每个人曾经获取的最小红包
}
printf("\r\n序号\t 总金额\t最大一包\t最小一包\t运气王次数\t衰神次数\r\n");
for (i = 0; i < peoples; i++) {
printf("%3d\t", i + 1);
printf("%5d.%02d元\t", total_money[i] / CENT_PER_YUAN, total_money[i] % CENT_PER_YUAN);
printf("%3d.%02d元\t", max_money[i] / CENT_PER_YUAN, max_money[i] % CENT_PER_YUAN);
printf("%2d.%02d元\t", min_money[i] / CENT_PER_YUAN, min_money[i] % CENT_PER_YUAN);
printf("\t%6d\t\t%6d\r\n\r\n", lucky_king[i], Decadence[i]);
}
printf("总金额方差:%lf\r\n", Cal_variance(peoples, total_money, CENT_PER_YUAN));
printf("最大红包方差:%lf\r\n", Cal_variance(peoples, max_money, CENT_PER_YUAN));
printf("最小红包方差:%lf\r\n", Cal_variance(peoples, min_money, CENT_PER_YUAN));
printf("运气王方差:%lf\r\n", Cal_variance(peoples, lucky_king, 1));
printf("衰神方差:%lf\r\n\r\n", Cal_variance(peoples, Decadence, 1));
free(money);
free(total_money);
free(lucky_king);
free(Decadence);
free(max_money);
free(min_money);
}
int main(int argc, char *argv[])
{
float amount;
int peoples, times;
if (argc > 1) {
amount = atof(argv[1]);
} else {
amount = 100.00; // 一次发100元红包
}
if (argc > 2) {
peoples = atoi(argv[2]);
} else {
peoples = 10; // 发给10个人
}
if (argc > 3) {
times = atoi(argv[3]);
} else {
times = 1000; // 发1000次
}
Red_Packet_nTimes((int)(amount * CENT_PER_YUAN), peoples, times);
return 0;
}
微信抢红包C语言版-线段切割法
最新推荐文章于 2021-05-23 10:54:30 发布