先上题目:
这道题一开始做的时候没认真审题,当成报数题做了,提交了几个0分发现问题不在代码,于是重新读了遍题。发现跟普通的报数不同的是,当一个人报出目标数后就会淘汰,于是就造成了循环周期的两个需求:
1.当前淘汰目标的下一个人需要接着他的数报 2.当前循环周期的下一个循环需要接着上一个周期的数字报,且周期-1
这需要数组能够记录每次报数的淘汰情况,并每更新一轮新的情况,就将原来的情况(称之为残局)覆盖。所以一维数组即可。数组的下标为选手的标签,数值则为所报数。这样每淘汰一人,数组就少一个元素,剩下的幸存者向前补位(补位过程只需一个简单的for遍历即可实现),直到只剩一个人时,数组的首元素即为winner。
为了让模拟容易实现,我还引入了工具tmp,num,pm,strat。具体作用是实现当前选手是当前周期的第几人,那么他就报自己的序号。有些复杂,读者可以在标程中慢慢理解。
标程
int main() {
int n = 0,k=0;
cin >> n>>k;
int cnt = 0;
int c;
int start = n;
int num = 1;
int m = n;//m是当前幸存者
int pm = 0;
int z[5+1] = { 0 };//记录每次报数残局
//每次一轮结束后(遍历走过了当前人数次) 更新淘汰人数(带标签) 不更新报数
//初始化第一轮 所有人都没被淘汰
for (int i = 0; i < n; i++) {
z[i] = i + 1;
}
while (m != 1) {
c = 0;
for (int i = 0; i < start; i++) {//遍历到本次周期的第i个
//所报数从第一个人开始 依次+1 不更新
if (num % k == 0 || num % 10 == k) {//第tmp人淘汰
int tmp = num;
tmp = num - pm;//实现这个人是第几个 他就报序号(下标+1)
//每淘汰一个人 就把这个人记作-1
z[tmp-1] = -1;//tmp-1是因为下标0
m--;
}
num++;
}
//模拟补位过程 其中start是这一轮开始时的人数 初始化为n
for (int i = 0; i <start; i++) {
if (z[i] != -1) {
z[c++] = z[i];
}
}
pm += start;
start = m;
//pm实现存迄今为止所有残局 这样num-pm使报数总从1开始
//z实现存每次残局 按序只存赋值为-1的
cnt++;
}
cout << z[0];
return 0;
}
这样能拿到九十分,超时代码。还没有想出优化方案,有大佬可以指点一下嘛
其实这个题早就写了,学期太忙拖到现在才写博客,要不是有注释已经看不懂自己写的什么意思了,注释真是个好东西啊🥰