猴子选大王(数组、链表实现)

猴子选大王

已知,有n只猴子,围绕成一圈,从第1只猴子开始报数1,第2只猴子报数2,以此类推,报数到m时,该猴子退出圈外。从下一只猴子开始,重新开始报数,每次报数到m时都会淘汰一只猴子,最后剩下的猴子为大王。请问,猴子大王的一开始的序号是多少?
首先这道题乍一看似乎如果用数组做,数组的下标会比较难处理,但我们可以略施小计来实现简化。

数组实现

先做好初始化

int n,m,i;//n为猴子总数,m为猴子所报的数 
	int cnt1=0;//记录所报的数 
	int cnt2=0;//记录被淘汰的猴子 
	int arr[1000];
	cin>>n>>m;
	//初始化 
	for(i=0;i<n;i++){
		arr[i]=1;//1表示在圈内 
	}

上核心思路

for(i=0;i<n;i++){
		if(arr[i]==1){
			cnt1++;//记录还存在的猴子
		}
		if(arr[i]==1&&cnt1%m==0){//该猴子还存在并且报数为m
			arr[i]=0;//0表示被淘汰 
			cnt2++;
		}
		if(cnt2==n-1){//淘汰猴子的数目为n-1时
			break;
		}
		if(i==(n-1)){//到数组末尾 
			i=-1;//把坐标移动到一开始 
		//(注意每轮循环结束 ,i++所以这里让 i=-1 ) 
		}
	}

最后来完整代码

#include<iostream>
using namespace std;
int arr[1000];
int main()
{
	int n,m,i;//n为猴子总数,m为猴子所报的数 
	int cnt1=0;//记录所报的数 
	int cnt2=0;//记录被淘汰的猴子 
	
	cin>>n>>m;
	//初始化 
	for(i=0;i<n;i++){
		arr[i]=1;//1表示在圈内 
	}
	for(i=0;i<n;i++){
		if(arr[i]==1){
			cnt1++;
		}
		if(arr[i]==1&&cnt1%m==0){
			arr[i]=0;//0表示被淘汰 
			cnt2++;
		}
		if(cnt2==n-1){//淘汰猴子的数目为n-1时
			break;
		}
		if(i==(n-1)){//到数组末尾 
			i=-1;//把坐标移动到一开始 
		//(注意每轮循环结束 ,i++所以这里让 i=-1 ) 
		}
	}
	for(i=0;i<n;i++){
		if(arr[i]==1){
			cout<<i+1;//输出所剩猴子的初始位置 
			//注意,一开始定义从0开始,可是实际情况为从1开始 
		}
	} 
	return 0;
}

链表实现

其实对于大多数已经学过链表的同学来说,链表虽然敲起来 麻烦 ,但是思路还是蛮好确定的。
直接上代码(环状链表)

#include<iostream>
#include<stdlib.h>
#include<malloc.h> 
using namespace std;
struct Monkey {
	int num;
	struct Monkey *next;
};
struct Monkey *create(int n){//创建环状链表,大小为n 
	struct Monkey *current,*next,*head;
	head=(struct Monkey*)malloc(sizeof(struct Monkey));//强制类型转换 
	head->num=1;
	head->next=NULL;//指向NULL,培养好习惯 
	current=head;
	int i=2;
	for(i=2;i<=n;i++){
		next=(struct Monkey*)malloc(sizeof(struct Monkey));
		next->num=i;
		current->next=next;
		current=next;
	}
	current->next=head;//构建环状链表
	return head; 
}
struct Monkey *del (struct Monkey *head,int i,int n){//i表示删除位置 ,n表示链表元素个数 
	struct Monkey *p,*q;
	p=head;
	q=p->next;
	int j=0;
	if(i==1){
	//如果删除第一个,则需要将最后一个和第二个连起来 
		for(j=1;j<n;j++){
			p=p->next;//找到最后一个 
		}
		p->next=q;//连接 
		if(n==2){//删除之后只剩一个结构体,所以让它指向空
			q->next=NULL;
		}
		return q;//返回 
	}else{
		for(j=1;j<i-1;j++){
			p=p->next;
			q=q->next;
		}
		p->next=q->next;
		if(n==2){
			q->next->next=NULL;
		}
		return q->next;//返回删除处的下一个 
	}
}
int main()
{
	int n,m;
	int cnt=0;
	cin>>n>>m;
	struct Monkey *head,*p;
	head=create(n);
	while(cnt<n-1){
		head=del(head,m,n-cnt);
		cnt++;
	}
	cout<<head->num<<endl;
	return 0;
 } 

我们还注意到,这里其实难点在del函数,要删除特定位置,并且返回它的下一位为头指针。

这是我觉得对于新手来说比较有意思的题目,欢迎大家多多补充多多讨论!
记得点赞哦!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值