题面
请在南京大学校园网环境下访问:🫡Jo 娜贝尔 (Bye-JonaBell.c) (cpl.icu)
题解
50 分算法
课上讲过的作业题 JoJo 谜题 (josephus.c) (cpl.icu)。
100 分算法
在模拟约瑟夫问题的过程中,增加一个数组 life[i]
,表示第 i
只 JonaBell 还有多少只尾巴。
当 life[i] == 0
时,意味着当前这只 JonaBell 已经出局,在数组中做标记,下次报数的时候跳过这只 JonaBell。
120 分算法
使用链表结构(后续课程会讲到)维护当前在游戏中的所有 JonaBell,这一优化可以大大提高算法效率,该算法可以处理 \(n=3000,k=3000\) 的数据规模。事实上这也是这道题目本来的第 10 个数据点的数据规模,后来出题人决定给大家一个拿满分的机会,缩小了数据规模的上限。
易错点
本题代码过于简单,没有易错点。
超越性的算法
如果有同学推算出根据 \(n,k,b,l\) 直接计算最终结果的通项公式,欢迎和出题助教联系。
标程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| #include <stdio.h>
const int N = 3005;
int main() {
int n, k, b, l; scanf("%d%d%d%d", &n, &k, &b, &l);
int pre[N], next[N]; for (int i = 1; i <= n; ++i) { pre[i] = i - 1; next[i] = i + 1; } pre[1] = n; next[n] = 1;
int life[N]; for (int i = 1; i <= n; ++i) { life[i] = l; }
int alive = n, cur = 1, cnt = 0, bullets = b; while (alive > 1) { if (++cnt == k) { cnt = 0; if (bullets > 0) { bullets--; if (--life[cur] == 0) { alive--; next[pre[cur]] = next[cur]; pre[next[cur]] = pre[cur]; } } else { bullets = b; } }
cur = next[cur]; }
for (int i = 1; i <= n; ++i) { if (life[i] > 0) { printf("%d\n", i); } }
return 0; }
|