Hrbust报数问题

news/2024/7/24 12:09:33 标签: 算法, 数据结构

题目描述

有 N 个人围成一圈,按顺时针给他们编号为 1-N。
紧接着,指定编号为 M 的人开始报数,报数按顺时针进行。
报到 D 的人出列,下一个人重新开始报数。按此规律,每次报到 D 的人都出列。
要求同学编程求出出列的顺序。
输入
输入包括多组测试用例。
对于每组用例,第一行是一个整数 N,表示人数。N<100。
接下来 N 行是每个人的人名。人名为长度不超过 20 连续字符串。
最后是以两个以","分割的整数 M,D。代表从 M 个人开始,每报 D 个数出列。
输出
输出所求的顺序
样例输入
8
Zhao
Qian
Sun
Li
Zhou
Wu
Zheng
Wang
4,4
样例输出
Zheng
Sun
Wang
Zhou
Li
Wu
Qian
Zhao

题目分析 

第一种思路:采用队列来解决这个问题,队列利用stl里面queue容器

第二种思路:采用循环链表来解决

 

第三种思路:用数组来模拟循环链表做这样一件事

另外我必须来说一下,怎样让游标可以在name数组中循环,也就是当指向最后一个数据之后,又会重新回到数组的开头进行循环轮替

(cur + 1) % n 这样一个代码就可以实现,比如当cur游标处在数组中最后一个位置的时候,也就是n-1这样一个位置,也就是说当前游标的下一个游标就是(n - 1 + 1) % n,也就是0,这个时候游标又回到了开头

代码实现 

第一种思路代码实现:

demo1.cpp

#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <queue>

using namespace std;

int main()
{
	int total_num;//总人数
	int start_num;//最起始位置
	int end_num;//每次结束报数位置
	char str[21] = {'\0'};
	//控制下整体的大循环
	while(scanf("%d",&total_num) != EOF) {
		//每次进来定义一个容器
		queue<string> q;
		//循环往里面放值
		while(total_num > 0) {
			scanf("%s",str);
			//输入之后入栈
			q.push(str);		
			total_num--;
		}
		//按照思路,先把第一个开始报数的人找到
		scanf("%d,%d",&start_num,&end_num);
		string top_elem;
		for(int i = 0;i < start_num - 1;i++) {
			//把除了第一个之外的数据都放到队列尾巴上面去
			top_elem = q.front();//栈顶元素
			q.pop();
			q.push(top_elem);
		}
		
		//开始整体执行判断操作
		while(q.size()) {			
			//下面开始进行报数找人
			for(int j = 0;j < end_num;j++) {
				//还是上面的方法
				top_elem = q.front();
				//拿到栈顶往后放
				q.pop();
				q.push(top_elem); 
			}
			//上面循环完了,此时栈顶元素就是我们想要的数
			printf("%s\n",q.front().c_str());
			//并且把这个数据给出栈掉
			q.pop();
		}

	}
	return 0;
}

第二种思路:循环链表代码实现

demo2.cpp

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int len = 0;

typedef struct _node{
	char name[21];
	struct _node *next;
}node;


node  *init_node() 
{
	node *p_head = (node *)malloc(sizeof(node));
	if(p_head != NULL) {
		//memset(p_head->name,'\0',sizeof(p_head->name));
		strcpy(p_head->name,"我是头结点");
		p_head->next = p_head;//循环链表指向自己
	}
	return p_head;
}

void insert_node(node *p_head,const char *name) 
{
	if(p_head != NULL && name != NULL) {
		node *p_node = (node*)malloc(sizeof(node));
		if(p_node != NULL) {
			//p_node->name = name;//字符串直接放到数组里面
			strcpy(p_node->name,name);//把name赋值到p_node->name指向的空间
			p_node->next = NULL;
			node *p_move = p_head;
			//把这个结点插入到链表的尾部
			for(int i = 0;i < len;i++) {
				p_move=p_move->next;
			}
			p_move->next = p_node;
			p_node->next = p_head;
			len++;//len是一个全局变量
		}
	}
}

//不要头结点只要数据结点,返回每一个结点地址
//拿到结点地址进行操作
node *insert_node1(node *p_head ,const char *name) 
{
	if(name != NULL) {
		node *p_node = (node *)malloc(sizeof(node));
		if(p_node != NULL) {
			strcpy(p_node->name,name);
			if(len == 0) {
				//说明这是一个头结点
				p_node->next = p_node;
			} else {
				//往下移动到最后一个数据
				if(p_head != NULL) {
					node *p_move = p_head;
					while(p_move->next != p_head){
						//指向最后一个结点
						p_move = p_move->next;
					}
					p_move->next = p_node;
					p_node->next = p_head;
				}
			}
			len++;			
		}
		return p_node;
	}
}

//根据节点地址删除数据
char* delete_node(node *p_head,node *p_node) 
{
	char *res = NULL;
	if(p_head != NULL && p_node != NULL && len > 0) {
		res = p_node->name;//字符串
		node *p_move = p_head;
		//移动到p_node的上一个节点
		while(p_move->next != p_node) {
			p_move = p_move->next;
		}
		p_move->next = p_node->next;
		len--;
	}
	return res;
}

//这里的删除操作我们是不需要头结点的
//为什么不需要头结点
//因为头结点也很有可能被删除
char *delete_node1(node *p_node) 
{
	char *res = NULL;
	//只需要移动到上一个结点然后进行删除操作就可以了
	if(p_node != NULL) {
		res = p_node->name;//这里返回一个字符串
		node *p_move = p_node;
		while(1) {
			if(p_move->next == p_node) {
				//程序跳出
				break;
			}	
			p_move = p_move->next;
		}
		//只要程序跳出之后,说明就已经指向了上一个删除结点上一个节点
		p_move->next = p_node->next;
		len--;
	}
	return res;
}


//打印数据
void print_node(node *p_head) 
{
	if(p_head != NULL && len > 1) {
		node *p_move = p_head->next;
		printf("%p %s %p\n",p_head,p_head->name,p_head->next);
		while(p_move != p_head) {
			printf(" %p %s %p\n",p_move,p_move->name,p_move->next);
			p_move = p_move->next;	
		}
	}
}


int main()
{	
	int total_num;
	scanf("%d",&total_num);
	char str[21] = {'\0'};
	scanf("%s",str);//数组作为参数会退化成为一级指针
	node *p1 = insert_node1(NULL,str);
	while(total_num > 1) {
		scanf("%s",str);
		insert_node1(p1,str);
		total_num--;
	}
	//确定好开始循环的指针位置
	int start,step_over;
	node *p_move = p1;//移动结点开始肯定是头结点
	scanf("%d,%d",&start,&step_over);
	for(int i = 0;i < start - 1;i++) {
		//开始进行移动
		p_move = p_move->next;
	}
	while(len) {
		for(int j = 0;j < step_over - 1;j++) {
			p_move = p_move->next;
		}
		char * res=delete_node1(p_move);//把这个节点删除,len会自动减少	
		//销毁了之后,给p_move重新赋上新值就可以了
		p_move = p_move->next;//p_node结点被删了,指向p_node结点的下一个结点
		printf("%s\n",res);
	}
	return 0;
}

这里循环链表我在多说一句,我想利用自己写的库来做,也就是自己写的一个循环链表容器解决问题

第三种思路代码实现

demo3.cpp

#include <stdio.h>
#include <stdlib.h>
#include <string.h>


//定义整体输入的数据大小
#define MAX_N 100
//定义字符串的最大长度
#define MAX_LEN 20

//定义数组来存储要进行出列大的字符串信息
char name[MAX_N][MAX_LEN + 1];
//定义一个标记数组来标记数组里面的每一个人是否已经出列
int out[MAX_N];
int n;//总人数

int main()
{
	//整体循环
	while(scanf("%d",&n) != EOF) {
		//循环输入数据到name数组里面
		for(int i = 0;i < n;i++) {
			scanf("%s",name[i]);
		}
		//初始化out数组这片空间
		//全部初始化为0表示没哟出队列
		memset(out,0,sizeof(out));
		int cur = 0;//游标开始的位置,每次前进两个游标
		int out_len = 0;//代表出对的个数,如果全部出队之后,个数应该是等于n
		int start_index,end_step;
		scanf("%d,%d",&start_index,&end_step);
		while(out_len < n) {
			int step = 0;
			while(step < end_step) {
				//让cur不断往下面前进,这也是它循环真正目的
				cur = (cur + 1) % n;
				//判断一下标记是否是有效前进值
				if(!out[cur]) {
					step++;
				}
			}
			//上面就会移动到我们需要出队的数据里面
			//把这个位置标记改了
			out[cur] = 1;
			out_len++;
			printf("%s\n",name[cur]);
		}
	}
	return 0;
}


http://www.niftyadmin.cn/n/152056.html

相关文章

HashMap的实际开发使用

目 录 前言 一、HashMap是什么&#xff1f; 二、使用步骤 1.解析一下它实现的原理 ​编辑 2.实际开发使用 总结 前言 本章&#xff0c;只是大概记录一下hashMap的简单使用方法&#xff0c;以及理清一下hashMap的put方法的原理&#xff0c;以及get方法的原理。 一、Has…

rar2john工具爆破rar文件

目录 1. 通过 rar2john 工具输出 rar 文件 hash 2. 通过 john 工具进行 rar 文件爆破 3. 查看爆破的密码

密钥用法标识

密钥用法&#xff1a; 数字签名 Digital Signature 认可签名 Non Repudiation 密钥加密 key Encipherment 数据加密 Data Encipherment 密钥协商 key Agreement 证书签名 Key CertSign CRL 签名 Crl Sign 仅仅加密 Encipher Only 仅仅解密 Decipher Only OpenSSL密钥…

beautifulSoup 【HTML树解析库】基本知识

文章目录1. 文档地址2. 安装3. 使用4. 解析器5. 对象的种类6. 遍历6.1 下行遍历6.2 上行遍历6.3 平行遍历7. 格式化与编码7.1 格式化7.2 编码1. 文档地址 beautifulSoup4 文档 2. 安装 pip3 install beautifulsoup43. 使用 from bs4 import BeautifulSoupsoup BeautifulSo…

【学习OpenCV4】基于OpenCV的手写数字识别

本内容分享于课程《OpenCV入门精讲&#xff08;C/Python双语教学&#xff09;》&#xff0c;地址&#xff1a; OpenCV入门精讲&#xff08;C/Python双语教学&#xff09; 如果想提升C的编程水平&#xff0c;可以参考课程&#xff1a; C进阶学习 OpenCV课程中还有很多有趣且…

迷宫 年号字串

题目 下图给出了一个迷宫的平面图&#xff0c;其中标记为 11 的为障碍&#xff0c;标记为 00 的为可以通行的地方。 010000 000100 001001 110000 迷宫的入口为左上角&#xff0c;出口为右下角&#xff0c;在迷宫中&#xff0c;只能从一个位置走到这 个它的上、下、左、右四个方…

Intro to Inversion of Control and Dependency Injection with Spring

What Is Inversion of Control? Inversion of Control is a principle in software engineering which transfers the control of objects or portions of a program to a container or framework. 在 Spring 中&#xff0c;类的实例化、依赖的实例化、依赖的传入都交由 Spr…

react源码解析16.concurrent模式

concurrent mode react17支持concurrent mode&#xff0c;这种模式的根本目的是为了让应用保持cpu和io的快速响应&#xff0c;它是一组新功能&#xff0c;包括Fiber、Scheduler、Lane&#xff0c;可以根据用户硬件性能和网络状况调整应用的响应速度&#xff0c;核心就是为了实…