有n个人,顺序排列, 并首尾相连围成一圈。从第一个人开始报数(从1到4),凡报到4的人退出圈子+扩展版本
https://blog.csdn.net/qq_44037213/article/details/106551760?fps=1&locationNum=2 有n个人(n<=1000),用1,2,...,n编号,顺序排列, 并首尾相连围成一圈。从第一个人开始报数(从1到4),凡报到4的人退出圈子, 且后面的人继续报数(同样从1到4报数),问最后留下的是原来第几号的那一位(用指针实现)。 输入 输入正整数n。 输出 输出最终留下的那个人的编号。 样例输入 53 样例输出 7 #include<stdio.h> #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); } }
扩展版本:
#include <stdio.h> #define N 1000 int main() { void dismiss(int n,int m,int s);/*声明函数*/ int n;/*学生规模*/ int m;/*报到m的同学离场*/ int s;/*从第s位同学开始报数*/ printf("输入n(学生规模),m(报到m的同学离场),s(从第s位同学开始报数):\n"); scanf_s("%d %d %d", &n,&m,&s);/*读入学生规模*/ dismiss(n,m,s);/*调用处理函数*/ return 0; } /*处理函数(包括打印)*/ void dismiss(int n,int m,int s) //m位同学 { int i, /*循环变量*/ j = 0, /*报数数码记录器j */ t = 0;/*记录已经离场的学生的数目*/ int identifier[N]; //保存编号identifier int* p = identifier; /*初始化数组*/ for (i = 1; i <= n; i++)/*[1,m]从1开始计数.*/ { *(p + i) =1; //通过指针创建/修改了数组里的内容(生成编号.) } //如果不对数组进行剪裁的话,则需要一个东西(这里定义了数码记录器j)来记录当前所报的数码(在1,2,3,4中循环) //在编号位没有被摸为零的,可使所报数码+1每报到数码4的时候,作剔除(摸零);从头开始报(1,2,3,4) /* 不得不说,这个for是巧妙的: 1.他的循环结束判断条件不是直接由循环变量i来控制的, 而是借助与另一个关键指标(变量t):被剔除的学生数目是否达到了(学生总数-1),即是否只剩一个同学在场了 那么i加到什么时候是个尽头?这无所谓了.*/ /* 这个for要实现当访问到尾的时候能够回到头部(通过 判断(是否末尾--若是,重置i 再扫描来实现) */ for (i = 1; t < n -1; i++)/*剩下一个人在场,共n-1个离场*/ { /* 该编号的同学是否已被抹去/有效,若有,使所报数码j++;如果使用的是0/1状态数组,可以省去判断,直接用一句:j += state[i];即可. */ /*if (identifier[i] != 0) j++;*/ j += identifier[i]; if (j == m) //所报数值累计到m的同学://而且每达到m,重置j= 0; { *(p + i) = 0; //赋值位0表示离开/抹去 j = 0; //重置数码记录器 t++; //记录被抹去了多少位同学.当该数值达到n-1时,则只剩下一个同学了,结束循环 } /* 判断是否到了结尾identifier[n] 了(最后一个元素的索引 n),处理回头问题. : 通过重置i=0为啥不是1?,因为回到for的时候会i++的identifier[1]..,*/ if (i >= n)/*若进入if,则说明第n个小朋友刚报数并检查过了*/ i = 0; } /*打印结果:*/ for (i = 1; i <= n; i++) { if (identifier[i] != 0)/*如果使用0/1 state[]数组,也是如此判断打印.*/ printf("%d", i); } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
2023-08-24 LA@非齐次线性方程组解的结构
2023-08-24 LA@齐次线性方程组解的结构
2023-08-24 LA@0线性方程组的解摘要@记号说明
2023-08-24 LA@向量组间的表示关系