n(n<20)个人站成一圈,逆时针编号为1~n。
有两个官员,A从1开始逆时针数,B从n开始顺时针数。
在每一轮中,官员A数k个就停下来,官员B数m个就停下来(注意有可能两个官员停在同一个人上)。
接下来被官员选中的人(1个或者2个)离开队伍。
输入n,k,m输出每轮里被选中的人的编号(如果有两个人,先输出被A选中的)。
例如,n=10,k=4,m=3,输出为4 8, 9 5, 3 1, 2 6, 10, 7。
注意:输出的每个数应当恰好占3列。
#include<stdio.h>
#include<iostream>
#include<String.h>
#define MAXN 81
using namespace std;
int n, k, m;
int A(int arr[], int start1, int k) //A返回从start1开始逆时针数停下的人
{
int i;
for(i = start1; ; i = (i+1) % n)
{
if(arr[i] == 0) continue;
else if(k == 1) break;
else k--;
}
return i+1;
}
int B(int arr[], int start2, int m) //B返回从start2开始顺时针数停下的人
{
int i;
for(i = start2; ; i = i == 0 ? n-1 : i-1 )
{
if(arr[i] == 0) continue;
else if(m == 1) break;
else m--;
}
return i+1;
}
int main()
{
scanf("%d %d %d", &n, &k, &m);
int n1 = n, start1 = 0 , start2 = n-1;
int arr[n] = {0};
for(int i = 0; i < n; i++)
arr[i] = i+1;
// print(arr, n);
while(n1!= 0)
{
int a = A(arr, start1, k), b = B(arr, start2, m);
if(a == b)
{
n1 -= 1;
printf("%3d\n", a);
arr[a-1] = 0; //被选中的位置设为零
start1 = a-1, start2 = a-1;// 重置起始位置
// print(arr, n);
}
else
{
n1 -= 2;
printf("%3d %3d\n", a, b);
arr[a-1] = 0, arr[b-1] = 0;//被选中的位置设为零
start1 = a-1, start2 = b-1;// 重置起始位置
// print(arr, n);
}
}
}
自己写的代码还是存在可以改进的地方,两个函数A和B很相似,都是逐步寻找第k个人,唯一不同的是寻找方向不同,因此可以考虑合并为一个函数,增加一个形参步长d代表方向,d=1表示逆时针,d=2表示顺时针。
int go(int p, int d, int t) {
while(t--) {
do { p = (p+d+n-1) % n + 1; } while(a[p] == 0); //走到下一个非0数字
}
return p;
}
改进的防溢出操作也写得很巧妙。