问题概述
编号为1至n的n个人围成一圈(之后编号为为i的人简称i)i在i+1左边,n在1的左边。
从1开始报数,i报完数后在他右边的人继续报数,如果i所报的数为m的倍数那么这个人就出圈
持续报数到只剩一个人
按出圈顺序输出编号。
方法1
我们设sta[i]为0表示i已经出圈,为1表示还在圈内
设pl为当前所处位置
如果一个人出圈就把sta修改为0
然后模拟报数过程并且跳过sta[i]=0的位置即可
#include<cstdio> const int N=1e5+5; int sta[N]; int main(){ int n,m; scanf("%d%d",&n,&m); for(int i=1;i<=n;++i) sta[i]=1; for(int i=1,pl=1;i<=n;++i) for(int j=m;j;){ if(sta[pl]){ --j; if(!j){ printf("%d ",pl); sta[pl]=0; } } pl++; if(pl>n) pl-=n; } return 0; }
方法2:
与之前的方法相似,只是用链表连接
删除时将其从链表中清除即可。
#include<cstdio> const int N=1e5+5; int nex[N],pre[N]; int main(){ int n,m; scanf("%d%d",&n,&m); for(int i=1;i<=n;++i) nex[i]=i+1,pre[i]=i-1; nex[n]=1;pre[1]=n; for(int i=1,pl=1;i<=n;++i){ for(int j=1;j<m;++j) pl=nex[pl]; printf("%d ",pl); int t=nex[pl]; pre[t]=pre[pl]; nex[pre[t]]=t; pl=t; } return 0; }
转载一个数学方法求输出序列中的最后一个:https://www.cnblogs.com/AllenDuane/p/3748203.html