数据结构练习——工人与石头

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


一、问题描述

本题要求用链表实现一个简单的模拟挖石头过程。

首先明确几个概念:

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;
}

总结

涉及随机数设置、链表实现、动态数组等重点,难点却在于如何理清实现过程和设置函数。
如有挪用,切记三连!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值