n(n<20)个人站成一圈,逆时针编号为 1~n。有两个官员,A从1开始逆时针数,B从n开始顺时针数。在每一轮中,官员 A 数个就停下来,官员 B数 m个就停下来(注意有可能两个官员停在同一个人上)。接下来被官员选中的人(1个或者2个)离开队伍。输入 n,k,m 输出每轮里被选中的人的编号(如果有两个人,先输出被 A 选中的)。
例如,n=10,k-4,m=3,输出为48,95,31,26,10,7。注意:输出的每个数应当恰好占3列。
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#define MAX 25
int n, k, m, a[MAX];
int go(int p, int d, int t);//p为起始位置,d表示顺时针还是逆时针,走t步
int main()
{
while (scanf("%d", &n) == 1 && n != 0) {
scanf("%d%d", &k, &m) == 2;
for (int i = 1; i <= n; i++) a[i] = i;
int left = n;
int p1 = n, p2 = 1;
while (left) {
p1 = go(p1, 1, k);
p2 = go(p2, -1, m);
printf("%3d", p1);
left--;
a[p1] = 0;
if (p1 != p2) {
printf("%3d", p2);
left--;
a[p2] = 0;
}
if (left) printf(",");
}
printf("\n");
}
return 0;
}
顺时针走和逆时针走两个函数合并,唯一区别只是走1步还是-1步;
d = 1 : p = p%n +1 d = -1 : p = (p-2+n)%n +1
取余后的取值为0~n-1,因此要再加一,所以d=1时要在原地,d=-1时要后退2步,因此统一后的表达式 p = (p+d+n-1)%n +1;
数k个人实际上是走k-1步,但每次被选中的人要离开队伍,因此要从新的为离开队伍的人开始数,及从离开的人的位置走k步,而第一轮是特殊情况,应该让第一轮的起始位置后退一步,及p1 =n,p2=1;
int go(int p, int d, int t)
{
while (t--) {
do {
p = ((p + d + n - 1) % n) + 1;
} while (a[p] == 0);
}
return p;
}