这个题目呢其实有两种思路。
第一种:就是可以给每一次找到的点打上标志,然后最后一个没有打上标志的就是最后一个点。
第二种:就是每一次退出一个我就将后面的数填充到那个空位置上,然后留下最后一个点就是答案。
第一种方法呢,就是需要一步一步地动,每动一步都需要判断这个点是否标志过。比较暴力。
第二种方法,可以直接计算,因为填补了空位置就可以直接用+(m-1)或者-(m-1)来运动,就会比较方便。
但是不管是第一种还是第二种都需要每次判断下标是否是合理的,并且做出相应的处理,就是不能出现负数和超过最大的下标的情况。
好啦,给个位官爷上代码喽:(代码中有很多注释,以方便理解)
#include <stdio.h>
#include <math.h>
#include <string.h>
//这个题目就是根据题意模拟
//这个题目呢有两个方向,一个是顺时针,一个是逆时针,而且每一个开始的位置都是这个这次时针的下一个
//每一次退出一个我就将后面的数填充到那个空位置上
int main(){
int k;
scanf("%d",&k);
while(k--){
int n,m;
scanf("%d%d",&n,&m);
int ans[n];
//初始化每个位置上人的序号
for(int i=0;i<n;i++) ans[i]=i+1;
int cnt=n-1,sta=0;
m--;//因为第一个点也算所以要减一。
while(cnt){//需要剩下一个人,因此需要循环n-1遍
sta=(sta+m)%n;//顺时针移动
cnt--;
for(int j=sta;j<n-1;j++) ans[j]=ans[j+1];//填充这个空位置,因为将后面的填充了这个空位,顺时针的时候也就相当于不用向后移动一个位置了
n--;//总人数减1
if(!cnt) break;//注意判断cnt是否为0
int ret=(sta-m);//逆时针移动
//abs()函数是取绝对值
sta=(ret+(abs(ret)/n+1)*n)%n;//减出来会有负数这一步操作就是将负数转换为正数
//具体分析一下这一步
//首先如果ret>0,那么(ret+(abs(ret)/n+1)*n)%n=ret%n;
//如果ret<0,那么我要让ret变成正数,首先我肯定要计算出ret比n大了多少,所以用abs(ret)/n表示abs(ret)是n的多少倍
//由于这个除法是向下取整的,因此我要增加一倍,也就是(abs(ret)/n+1)*n
//然后最终结果取余n就好
cnt--;
for(int j=sta;j<n-1;j++) ans[j]=ans[j+1];//填充这个空位置,注意这一步是顺时针填充,因为逆时针填充很麻烦,因此sta要逆时针走一步
n--;//总人数减一
sta=(sta-1+n)%n;//因为逆时针是反向移动的,但是我填充是正向填充的,所以不一样
}
printf("%d\n",ans[0]);//输出最后一个人
}
return 0;
}
继续加油哦,我们明天再见!