有n个人,顺序排列, 并首尾相连围成一圈。从第一个人开始报数(从1到4),凡报到4的人退出圈子,

https://blog.csdn.net/qq_44037213/article/details/106551760?fps=1&locationNum=2
有n个人(n<=1000),用1,2,...,n编号,顺序排列,
 并首尾相连围成一圈。从第一个人开始报数(14),凡报到4的人退出圈子,
 且后面的人继续报数(同样从14报数),问最后留下的是原来第几号的那一位(用指针实现)。

输入
输入正整数n。

输出
输出最终留下的那个人的编号。

样例输入
53
样例输出
7


#include
#define N 1000
int main()
{
	void dismiss(int m);
	int n;
	scanf("%d",&n);

	dismiss(n);
	return 0;
}
void dismiss(int m)//m位同学
{
	int i,j=0,t=0;
    int identifier[N];//保存编号identifier
	int *p = identifier;

	for(i=0;i<m;i++)
	{
		*(p+i)=i+1;//通过指针创建/修改了数组里的内容()
	}

//如果不对数组进行剪裁的话,则需要一个东西(这里定义了数码记录器j)来记录当前所报的数码(在1,2,3,4中循环)
//在编号位没有被摸为零的,可使所报数码+1每报到数码4的时候,作剔除(摸零);从头开始报(1,2,3,4)
/* 不得不说,这个for是巧妙的:
1.他的循环结束判断条件不是直接由循环变量i来控制的,
而是借助与另一个关键指标(变量t):被剔除的学生数目是否达到了(学生总数-1),即是否只剩一个同学在场了 
那么i加到什么时候是个尽头?*/
/* 这个for要实现当访问到尾的时候能够回到头部(通过 判断(是否末尾--若是,重置i  再扫描来实现) */
	for(i=0; t<m-1 ;i++)//运行m次
	{
        /* 该编号的同学是否已被抹去/有效,若有,使所报数码j++ */
		if(identifier[i]!=0)
			j++;

		if(j==4)//所报数值累计到4的同学://而且每达到4,重置j= 0;
		{
			*(p+i)=0;//赋值位0表示离开/抹去

			j=0;//重置数码记录器
			t++;//记录被抹去了多少位同学.当该数值达到n-1时,则只剩下一个同学了,结束循环
		}
        /* 判断是否到了结尾identifier[m-1] 了(最后一个元素的索引 m-1),处理回头问题. :
        通过重置i=-1为啥不是0?,因为回到for的时候会i++的identifier[0]..,*/
		if(i>=m-1)
			i=-1;
	}


	for(i=0;i<m;i++)
	{
		if(identifier[i]!=0)
		printf("%d",i+1);
	}
}


你可能感兴趣的:(笔记)