初学者对于约瑟夫环问题的几次尝试

第一次遇到的题目是“猴子选大王”,之后又遇到了几次,索性将我的新手思路记录一下…… 题目(最简单版):

n个人围成一圈开始报数,数到m的人出列,下一个人接着从1开始报数,问最后剩下的那个是几号。

近两个月的解答: 第一次:当时刚刚接触编程,不知道怎么让他循环,用的是二维数组。

#include<stdio.h>
void search(int);
int main()
{
	int n=6;
	search(n);
	return 0;
}	
void search(int n)
{
	int x,y,k=6,i=0,a[6][6];
	for(x=0;x<n;x++)
	   for(y=0;y<n;y++)
	      a[y][x]=1;//数组为1 
	for(y=0;y<n&&k>1;y++)
	{
		for(x=0;x<n;x++)
		{
			if(a[y][x]!=0)
				i++;
			if(i==4)
			{
				for(k=0;k<n;k++)
					a[k][x]=0;//逢数到4的列数其元素都为0,此列失去称王机会 
				i=0;
			}
		}
	    k=0;//切记不可放在循环里! 
		for(x=0;x<n;x++) 
		{	
			k=k+a[0][x];//判定是否只剩下一个数 
		}			
	}
	for(x=0;x<n;x++)
		if(a[0][x]==1)
			printf("%d",x+1);
}

第二次:看了老师PPT上的解答当时觉得很精彩,但私以为相比于之后的几种思路,这个有点难懂~其实作为初学者,到目前为止每次看书上的解答代码都觉得好精彩……

#include<stdio.h>
int main()
{
	int a[7],i,pre,count=0;
	for(i=1;i<=6;i++)
		a[i]=i+1;//下标对应的元素表示他的下一个人 
	a[6]=1;
	i=6;
	while(a[i]!=i)//他的下一个人不是他自己,继续循环 
	{
		pre=i;//a[pre]是i,也是当前的人的号码
		i=a[i];//i从1开始  
		count++;
		if(count%4==0)//数到4下去一个 
		{
			a[pre]=a[i];//从此这个号码消失,转变为他的下一个人 
			i=pre;
		}
	}
	printf("%d",i);
	return 0;
 } 

第三次:刚开始主动接触算法,大概看了眼书然后照猫画虎写了个跟人家不一样的选大王……

#include<iostream>
using namespace std;
bool a[100];//为1时表示已出列 
int main()
{
	int n,m;
	cin>>n>>m;
	int count=0,temp=0;//temp记录当前位置 
	int record=n;//record记录剩下的人数 
	while(1)
	{
		while(1)
		{
			temp++;
			if(temp==n+1)
				temp=1;
			if(a[temp]==0)
				break;
		}
		if(record==1)
			break;
		count++;
		if(count%m==0)
		{
			a[temp]=1;
			record--;
		}		
	}
	cout<<temp;
	return 0;
}

第四次:书上的解答,思路易懂,比上面我写的好多啦

#include<iostream>
#include<cstring>
using namespace std;
bool a[100];
int main()
{
	int n,m,k,temp=0,count=0,person=0;
	memset(a,false,sizeof(a));//瞎学归零~ 
	cin>>n>>m;
	do
	{
		temp++;
		if(temp==n+1)
			temp=1;
		if(a[temp]==false)
			count++;
		if(count==m)//此处不能写为count%m==0,这样的话一旦两个人连着true,person就增加了 
		{
			count=0;
			k=temp;
			a[temp]=true;
			person++;
		}	
	}while(person<n); 
	cout<<k;
	return 0;
}

第五次:看链表时果断还有这题……于是用了个单向循环链表,不过和书上的链表构建方法不太一样,因为之前看《啊哈算法》时被那里介绍的链表写法先入为主了。

#include<iostream>
using namespace std;
struct node
{
	int num;
	node *next;
};
int main()
{
	node *head=NULL,*p,*q;
	int n,m,x;
	cin>>n>>m;
	//建立链表 
	for(int i=1;i<=n;i++)
	{
		p=new node;
		p->num=i;
		if(head==NULL)
			head=p;
		else
			q->next=p;
		q=p;
	}
	q->next=head;//循环上啦 
	
	for(int i=1;i<n;i++)
	{
		for(int j=1;j<m;j++)
		{
			p=p->next;
		}//找到,并弃掉这个结构体 
		p->next=p->next->next;
	}
	cout<<p->num;
	return 0;
}

第六次:(对这题是真爱~)模拟链表,也是和第二次老师PPT一样用数组值来记录下一个人的序号,但个人觉得更简洁也更好理解一些。

#include<iostream>
using namespace std;
int main()
{
	int n,m,a[30];
	cin>>n>>m;
	for(int i=1;i<n;i++)
		a[i]=i+1;
	a[n]=1;//循环上啦 
	int temp=n;
	for(int person=0;person<n;person++)//每回合出去一个人直到n人为止 
	{
		for(int k=1;k<m;k++)//用这种写法数到m后,需要出列的人是a[temp] 
		{
			temp=a[temp];
		}
		cout<<a[temp]<<" ";//这次是输出出列顺序了 
		a[temp]=a[a[temp]]; //这里就像链表的next指针一样,指向下一个的下一个 
	}
	return 0;
}

 对于这道题写到目前这个程度的总结就是:                 想个办法让他循环,要么模拟个循环链表,要么让temp(名字随意啦)数到n+1时变成1,然后只要按题目要求照做就好了。

    原文作者:约瑟夫环问题
    原文地址: https://blog.csdn.net/AlphaWA/article/details/79298961
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞