本文已参加[新人创作礼]活动,一起开启掘金创作之路。
有 n 个人围成一圈,顺序排号。从第一个人开始报数(从 1 报到 3),凡是报到 3 的人退出圈子,问最后留下的是原来第几号的那位。
就是逢3筛出来,然后按照出局的人数还剩一人结束循环
这里我使用二种方法:
1. 数组
#include <stdio.h>
#define N 3 //人数
int main()
{
int a[N]={0}; //全部初始化为0,每人都是0
int i=0,t;
int count=0;
int leave=N; //剩下的人数
printf("原来是:\n");
for(t=0;t<N;t++) printf("%d ",a[t]); //原来是
printf("\n");
printf("下面是循环过程:\n");
while (leave!=1){ //一直循环到最后留下了一人
if(a[i]==0) count++; //如果没有淘汰 count++
if(count%3==0) { //逢3筛出来
a[i]=1;
leave--;
for(t=0;t<N;t++) printf("%d ",a[t]); //输出筛选过程
printf("\n");
}
i=(i+1)%N; //跳到值为0的下一个人
while(a[i]!=0){ //跳过上次已经去掉的序号3的那个,直接到下一个人
i=(i+1)%N;
}
}
printf("剩下的是原来的第%d号\n",i+1);
return 0;
}
可能看着不太理解,你带入一下,
利用这个例子:
原来是 0 0 0 3个人
开始
-
i=0 leave=3 a[i]==0 表示不是出局的人 count++ (1)
i=(i+1)%N; i=1 下一个人 -
i=1 leave=3 a[i]==0 表示不是出局的人 count++ (2)
i=(i+1)%N; i=2 下一个人 -
i=2 leave=3 a[i]==0 表示不是出局的人 count++ (3) 此时if(count%3==0) {
筛3出来,a[2]=1 leave=2,输出第一次筛选的过程 0 0 1
i=(i+1)%N; i变为0 -
i=0 leave=2 a[i]==0 表示不是出局的人 count++ (4)
i=(i+1)%N; i=1 下一个人 -
i=1 leave=2 a[i]==0 表示不是出局的人 count++ (5)
i=(i+1)%N; i=2下一个人
这时候
while(a[i]!=0){ //跳过上次已经去掉的序号3的那个,直接到下一个人i=(i+1)%N; }
a[2]!=0 所以i=(i+1)%N; 跳过上次被去掉的人 直接下一个 i=0 -
i=0 leave=2 a[i]==0 表示不是出局的人 count++ (6) 此时if(count%3==0) {
筛3出来,a[0]=1 leave=1,输出第一次筛选的过程 1 0 1
i=(i+1)%N; i=1下一个人
这时候while (leave!=1)
leave=1 所以循环结束 -
printf("剩下的是原来的第%d号\n",i+1);
2. 指针数组
#include <stdio.h>
#define N 3 //人数
int main()
{
int a[N] = {0}, out = 0, num = 0, *flag;
flag = a; //指向首地址
while (1){ //循环报数
if(*flag == 0){ //如果没有淘汰 0表示没出局
if (out == (N - 1)) break; //如果仅剩一人,结束
num++; //报数 +1+1
num %= 3; //最大为3,到了3就从0开始 逢3筛出来
if(num == 0) //为0(即3)出局
{
*flag = 1; //出局,*flag变为1标志 1表示出局
out++; //出局人+1
}
}
flag++; //下一个人
if (flag == a + N) //如果flag的地址等于(a的首地址+N)的地址
flag = a; //重新从首地址开始,第二次筛选
}
printf("最后剩余者的编号是: %ld\n", flag-a+1); //打印那个最后值的地址
}
这个跟上面的思路差不多
- 开始 0 0 0 out出局0 num=0
- flag=a,指向首地址
- *flag==0 表示没出局 num++ (1)
- flag++ 下一个人地址 a+1 num++(2)
- flag++ 下一个人地址 a+2 num++(3)
- num %= 3; if(num == 0) //为0(即3)出局
- *flag = 1 out++(1)
- 这时候为 0 0 1
- flag++ 下一个人地址,但是等于a+N 超过数组长度
- 这时候flag地址超过a长度 为a+N
- flag=a 重新首地址开始
- 第二轮
- *flag==0 表示没出局 num++ (4)
- flag++ 下一个人地址 a+1
- *flag==0 表示没出局 num++ (5)
- a+2 *flag=1 if(*flag == 0){ 直接不满足 下一个flag++ a+3
- 这时候flag地址超过a长度 为a+N flag=a 重新首地址开始
- *flag==0 表示没出局 num++ (6)
- num %= 3; if(num == 0) //为0(即3)出局
- *flag = 1 out++(2)
- if (out == (N - 1)) break;
- 结束
- 这时候数组为 1 0 1
- 输出
- printf("最后剩余者的编号是: %ld\n", flag-a+1); //打印那个最后值的地址
- 打印的是地址
- 可以使用%p打印但是是十六进制,这里使用flag-a首地址 再+1 来表示flag此时的地址
- 这样打印出来就是int型