(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列。
思路:
救济金的问题抽象出来就是几个人围成一个圈坐,给每一个人编号,一个人从1开始,一个人从n开始,从一开始的点到k时,出列一人,n逆时针点人,点到m出列一人。如果我们出列用删除操作,则大大的降低了效率,我们将删除掉的人用0来代替,当我们遇到0时直接跳过。
我们数数时,在起始位置时,由于是一个圆圈,我们可以设置从一数的时候从最后一个位置起始,最后位置数数的时候从起始位置起。即p从1开始,把1包含里面,所以从n开始逆时针数;同理,为了把n包含在里面,q从1开始顺时针数。
while(t–)执行的循环次数是t次;每次走p = (p + q + n-1)%n + 1(把顺时针的合并所以加上了n-1)。
#include"stdio.h"
#define max 20
int n,k,m;
int a[max];
int go(int p,int q,int t){
while(t--){
do{
p=(p+q+n-1)%n + 1;
}while(a[p]==0);
}
return p;
}
int main()
{
int i;
int p;
int q;
int left_num;
scanf("%d %d %d",&n,&k,&m);
for(i=1;i<=n;i++){
a[i]=i;
}
left_num = n;
p=n;
q=1;
while(left_num)
{
p=go(p,1,k);
q=go(q,-1,m);
printf("%3d",p);
left_num--;
if(q!=p)
{
printf("%3d",q);
left_num--;
}
a[p] = a[q] = 0;//标记走过的位置
if(left_num) printf(",");
}
printf("\n");
}