例题4-3 救济金发放(The Dole Queue, UVa 133)

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列。

【分析】
仍然采用自顶向下的方法编写程序。用一个大小为0的数组表示人站成的圈。为了避免 人走之后移动数组元素,用0表示离开队伍的人,数数时跳过即可。主程序如下:
 

代码中取余用的很好,很巧妙;完美的实现了循环;用我们    (此时的位置+走的方向+总人数-1)%总人数 = 下一个人位置

然后循环要走几次,遇到0,就跳过,继续走,当走完固定的步数后,就得到了我们想要的那个人;

#include<iostream>
#include<cstdio>
#define Max 25
using namespace std;

int a[Max];
int n,A,B;

int Go(int id,int dir,int t)
{
    while(t--)
    {
        do
        {
            id=(id+dir+n-1)%n+1;
        }while(a[id]==0);
    }
    return id;
}

int main()
{
    scanf("%d%d%d",&n,&A,&B);
    for(int i=1;i<=n;i++)
    {
        a[i]=i;
    }
    int left = n;
    int q=1,p=n;
    // 1为逆时针走,-1为顺时针走
    while(left)
    {
        q=Go(q,1,A-1);
        p=Go(p,-1,B-1);
        //因为我们当前站的那个位置也要数,所以只需要再走A-1或B-1步
        printf("%d",q);
        left--;
        if(q!=p)
        {
            printf("%d",p);
            left--;
        }
        a[q]=a[p]=0;
        if(left)
            printf(",");
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_40099908/article/details/81741720