题目
模拟约瑟夫环:n 人报数 m 出列
思路
本题模拟约瑟夫环:n 人围圈报数 m,第 m 个出列,直到剩一人或输出出列顺序。
可用数组标记存活或链表模拟;从当前位置数 m 个活人,出局后继续从下一位报数,直到满足题面停止条件。
解题分析
约瑟夫环模拟:数组标记是否出局,从当前位置报数到 m 的出局,下一位继续,直到剩 0 人。n、m 不大时 O(n²) 模拟足够;n 很大时有递推公式 O(n),但理解成本高,练手先用模拟。
完整程序
#include <stdio.h>
int main(void)
{
int n, m;
if (scanf("%d %d", &n, &m) != 2 || n < 1 || m < 1) {
return 1;
}
int alive[1000];
for (int i = 0; i < n; i++) {
alive[i] = 1;
}
int left = n, i = 0, cnt = 0;
while (left) {
if (alive[i]) {
cnt++;
if (cnt == m) {
printf("%d ", i + 1);
alive[i] = 0;
left--;
cnt = 0;
}
}
i = (i + 1) % n;
}
putchar('\n');
return 0;
}
运行示例
输入:
5 2输出:
2 4 1 5 3 其它写法
下面每种写法都是完整程序,输入输出格式与正文一致,便于对照。
数组标记模拟(与正文同类)
正文已是数组模拟,此处保留完整程序便于与链表思路对照。
程序:
#include <stdio.h>
int main(void)
{
int n, m;
if (scanf("%d %d", &n, &m) != 2 || n < 1 || m < 1) {
return 1;
}
int alive[1000];
for (int i = 0; i < n; i++) {
alive[i] = 1;
}
int left = n, i = 0, cnt = 0;
while (left) {
if (alive[i]) {
cnt++;
if (cnt == m) {
printf("%d ", i + 1);
alive[i] = 0;
left--;
cnt = 0;
}
}
i = (i + 1) % n;
}
putchar('\n');
return 0;
}运行示例
输入:
5 2输出:
2 4 1 5 3