1. 程式人生 > >例題4-3 救濟金髮放(The Dole Queue, UVa 133)

例題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;
}