题目描述
问题描述
有n个小朋友围成一圈玩游戏,小朋友从1至n编号,2号小朋友坐在1号小朋友的顺时针方向,3号小朋友坐在2号小朋友的顺时针方向,……,1号小朋友坐在n号小朋友的顺时针方向。
游戏开始,从1号小朋友开始顺时针报数,接下来每个小朋友的报数是上一个小朋友报的数加1。若一个小朋友报的数为k的倍数或其末位数(即数的个位)为k,则该小朋友被淘汰出局,不再参加以后的报数。当游戏中只剩下一个小朋友时,该小朋友获胜。
例如,当n=5, k=2时:
1号小朋友报数1;
2号小朋友报数2淘汰;
3号小朋友报数3;
4号小朋友报数4淘汰;
5号小朋友报数5;
1号小朋友报数6淘汰;
3号小朋友报数7;
5号小朋友报数8淘汰;
3号小朋友获胜。
给定n和k,请问最后获胜的小朋友编号为多少?
输入格式
输入一行,包括两个整数n和k,意义如题目所述。
输出格式
输出一行,包含一个整数,表示获胜的小朋友编号。
样例输入
5 2
样例输出
3
样例输入
7 3
样例输出
4
数据规模和约定
对于所有评测用例,1 ≤ n ≤ 1000,1 ≤ k ≤ 9。
题解1
模拟题意,注意处理起始队列只有1个人的特殊情况。每次到达队尾需要判断当队列中的人数是否为1,是的话就达到结束条件,否则回到队首,继续执行相关操作。
代码1
#include<bits/stdc++.h>
using namespace std;
#define MAX (1000 + 5)
bool mark[MAX];
int getNum(int n, int &res){//获取当前队列中的人数
bool flag = false;
int cnt = 0;
for(int i = 1; i <= n; ++i){
if(!mark[i]){
if(!flag){
res = i;
flag = true;
}
++cnt;
}
}
return cnt;
}
int deal(int n, int k) {
int num = 0, idx = 1, res = 0;
while(true){
if(getNum(n, res) == 1){//处理1 k等特殊情况
break;
}
if(!mark[idx]){//未出队
++num;
if(num % k == 0 || num % 10 == k){//末数为k或者数为k的倍数
mark[idx] = true;
}
}
if(idx == n){//到尾的时候考虑是否满足只有一个人的结束条件
if(getNum(n, res) == 1){
break;
}
idx = 1;
}
else{
idx = idx + 1;
}
}
return res;
}
int main(){
//freopen("E://a.txt", "r", stdin);
memset(mark, false, sizeof(mark));//初始化
int n, k;
scanf("%d%d", &n, &k);
printf("%d\n", deal(n, k));
return 0;
}
题解2
使用2个队列来模拟
代码2
#include<bits/stdc++.h>
using namespace std;
int deal(int n, int k) {
queue<int>que[2];
for(int i = 1; i <= n; ++i){//初始化队列
que[0].push(i);
}
int cnt = 0, frt;
while(que[0].size() + que[1].size() > 1){
int idx = 0;
while(que[idx].empty())idx++;//寻找非空的队列
while(!que[idx].empty()){//报数出队
++cnt;
frt = que[idx].front();
que[idx].pop();
if(cnt % k != 0 && cnt % 10 != k){//未出队存放在另一个队列中
que[1 - idx].push(frt);
}
if(que[idx].size() + que[1 - idx].size() == 1){//处理2 1 的情况
break;
}
}
}
int idx = 0;
while(que[idx].empty())idx++;
return que[idx].front();
}
int main(){
//freopen("E://a.txt", "r", stdin);
int n, k;
scanf("%d%d", &n, &k);
printf("%d\n", deal(n, k));
return 0;
}