提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
一、问题描述
本题要求用链表实现一个简单的模拟挖石头过程。
首先明确几个概念:
worker:
挖石头者。每个挖石头者挖石头能力不同。这里以一天为一个时间片段,假设 worker A 的挖石头能力为 a(0<a<1000),则意味着每一天这个 worker A 都能够产生 a 个随机数。每个随机数从整数 [1, 2, 3…1000] 中随机产生。如
果一个随机数 t 满足 t∈[991, 992, 993…1000], 那么 worker
A 在这一天“挖到石头”。如果 worker A 在一天中产生的 a 个随机数中有 b 个数字满足在 [991, 992, 993…1000] 的范围里,那么 worker A
在这一天 “挖到石头”的次数为 b。
挖石头奖励:
每天只有 50 个金币作为奖励,并且这 50 个金币只能全部奖励给一个 worker, 所以 worker 之间存在竞争关系。假如在这一天中,所有的 worker 都没有“挖到石头”,即他们的 “挖到石头” 的次数都为 0,那么这一天所有的 worker 都没有获得奖励。假如在这一天中,只有一个 worker “挖到石头”,那么无论他“挖到石头”的次数为多少,这 50 个金币都奖励给他。假如这一天中,多个 worker “挖到石头”,那么这 50 个金币奖励给某一个 worker 的概率正比于他“挖到石头”的次数。例如,这一天中,worker A “挖到石头” 的次数为 3,worker B “挖到石头” 的次数为 2,worker C “挖到石头” 的次数为 0,那么这一天这 50 个金币奖励给worker A 的概率为 3/5,奖励给 worker B 的概率为 2/5。
单链表:
一个单链表被用来记录挖石头奖励的信息。挖石头开始前,链表为空或只有表头指针。每当一个 worker 被奖励 50 个金币时,添加一个链表节点到单链表的尾部。链表节点中保存此次奖励的信息,如被奖励的 worker 是谁,奖励了多少个金币,当前是哪一天等等。请自行定义链表节点的结构。
程序目标
你需要自己定义所需要的结构体和链表,自己实现模拟挖石头过程。然后,根据输入的参数来进行模拟挖石头,挖石头结束后输出每个 worker 的奖励结果。
例子输入
10 20 30
1000
第一行的 3 代表 3 个 worker。
第二行的 3 个数字分别表示第一个 worker 到第三个 worker 的挖石头能力, 用空格隔开。
第三行的 1000 表示模拟挖石头的进行总天数。
例子输出
worker 1: 4700
worker 2: 10150
worker 3: 14900
二、实现代码
仔细看注释:
#define _CRT_SECURE_NO_WARNINGS 1
#define num_coin 50
#define min_num 991
#define max_num 1000
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
typedef struct Information_List
{
int work_rank;
int coin_num;
int day;
struct Information_List* next;
}InfoList;
//创建存放信息的节点
InfoList* CreateNode(int work_rank, int coin_num, int day)
{
InfoList* ret = (InfoList*)malloc(sizeof(InfoList));
ret->work_rank = work_rank;
ret->coin_num = coin_num;
ret->day = day;
ret->next = NULL;
return ret;
}
//向链表中添加获奖信息
void add_information(InfoList* phead, int work_rank, int coin_num, int day)
{
InfoList* tem = phead;
//找到链表尾部
while (tem->next != NULL)
{
tem = tem->next;
}
InfoList* newnode = CreateNode(work_rank, coin_num, day);
tem->next = newnode;
}
//记录一个工人某天的挖石头结果
void end_mining(int work_rank,int* work_capa, int* end)
{
int i = 0, num = 0;
//记录挖到石头的次数
int count = 0;
for (i = 0; i < work_capa[work_rank]; i++)
{
num = rand() % 1000+1;
if (num >= min_num && num <= max_num)
{
count++;
}
}
//记录该工人的挖石头结果
end[work_rank] = count;
}
//判断该天工人的挖石头奖励并记录
void judge_award(int work_num ,int day, int* end,InfoList* phead)
{
int i = 0;
int sum = 0;
for (i = 0; i < work_num; i++)
{
sum += end[i];
}
//没有人挖到石头
if (sum == 0)
{
return;
}
//有人挖到石头
else
{
int* judge_arr = (int*)malloc(sizeof(int) * sum);
//处理获奖概率
int j = 0;
for (i = 0; i < work_num; i++)
{
while (end[i]--)
{
judge_arr[j] = i;
j++;
}
}
//judge_arr[judge_num]就是获奖工人所在下标
int judge_num = rand() % sum;
//记录获奖信息
add_information(phead, judge_arr[judge_num], num_coin, day);
return;
}
}
//打印获奖信息
void print_information(InfoList* phead)
{
InfoList* tem = phead->next;
while (tem != NULL)
{
printf("\t获奖人:%d 获奖金额:%d 获奖时间:%d 天\n", tem->work_rank + 1, tem->coin_num, tem->day+1);
tem = tem->next;
}
}
//打印
void print(InfoList* phead,int work_num)
{
InfoList* tem = phead->next;
int* coin_of_worker = (int*)calloc(work_num,sizeof(int));
while (tem != NULL)
{
coin_of_worker[tem->work_rank] += num_coin;
tem = tem->next;
}
for (int i = 0; i < work_num; i++)
{
if (coin_of_worker[i] != 0)
{
printf("\tworker %d: %d\n", i + 1, coin_of_worker[i]);
}
}
}
int main()
{
//设置随机数种子
srand((size_t)time(NULL));
//输入工人人数
int work_num = 0;
scanf("%d", &work_num);
char ch = getchar();
//输入每个工人的挖石头的能力
int* work_capa = (int*)calloc(work_num,sizeof(int));
int i = 0,j=0;
for (i = 0; i < work_num; i++)
{
scanf("%d", &work_capa[i]);
}
ch = getchar();
//输入挖石头的天数
int day = 0;
scanf("%d", &day);
//设置存储获奖信息的链表
InfoList* phead = (InfoList*)malloc(sizeof(InfoList));
phead->next = NULL;
//每天每个工人的挖矿结果
int* end = (int*)malloc(sizeof(int) * work_num);
//遍历每一天
for (i = 0; i < day; i++)
{
//遍历每一个工人
for (j = 0; j < work_num; j++)
{
//记录工人的挖石头结果
end_mining(j, work_capa, end);
}
//判断该天工人的挖石头奖励并记录
judge_award(work_num, i, end, phead);
}
//打印获奖信息
print_information(phead);
print(phead, work_num);
free(work_capa);
free(phead);
return 0;
}
总结
涉及随机数设置、链表实现、动态数组等重点,难点却在于如何理清实现过程和设置函数。
如有挪用,切记三连!