问题概述

编号为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