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

例題 4-3 救濟金髮放(The Dole Queue) UVa 133

題目:

為了縮短領救濟品的隊伍,NNGLRP決定了以下策略:每天所有來申請救濟品的人會被放在一個大圓圈,面朝裡面。選定一個人為編號 1 號,其他的就從那個人開始逆時針開始編號直到 N。一個官員一開始逆時針數,數 k 個申請者,然後另一個官員第 N 個始順時針方向數 m 個申請者,這兩個人就出圓圈。如果兩個官員數的是同一個人,那個人則出圈,如果選了兩個不同的人,則先輸出第一個第一個官員數出的那個人,然後2個官員再在剩下的人裡面繼續選直到沒人剩下來,注意兩個被選 中的人是同時走掉的,所以就有可能兩個官員選中一個人。

#include<stdio.h>
#include<string.h>
#define maxn 1000
int a[maxn];
int n, k, m;
int go(int p, int d, int t) //巧妙 
	{
		while(t--){
			do{
				p = (p+d+n)%n;
			}while(a[p] == 0);
		}
		return p;
	}
int main()
	{
		int people;
		while(scanf("%d%d%d",&n,&k,&m) == 3 && !(n == 0 && k == 0 && m == 0)){
			for(int i = 0; i < n; i++ ){
				a[i] = i+1;
			}
			int left = n;//剩餘 人數 
			int p1 = n-1, p2 = 0; // p指向起始處的前一個位置 
			while(left){
				p1 = go(p1, 1, k);
				p2 = go(p2, -1, m);
				printf("%3d", p1+1);//注意 出隊人的序號比索引大 1 (陣列下標從零開始的)
				left--;
				if(p2 != p1){
					printf("%3d",p2+1);
					left--;
				}
				a[p1] = a[p2] = 0;
				if(left)
					printf(",");	
			}
			printf("\n");
		}
		
		return 0;
	}
go函式每走一步都得到下一個位置 解析:至於下一個位置為什麼是p = (p+n+d)%n.其實很簡單。因為我們是一步步走的,所以只有兩種邊界情況。假設當前位置是p(0=<p<n),
第一種邊界:p + 1 > n - 1,即 p + 1此時應該是到達0位置,但此時p + 1 = n,如果我們取餘數,則 (p+1)%T = 0,T = n(T表示這個圓圈的週期大小)。
剛好能符合,又因為T = n,所以(P+T+1)%T還是不變的。
第二種邊界: p - 1 < 0, 即 p - 1此時的值是-1,對於這種情況可以反過來看,它是向後退後1個單位,可以看成向前走T - 1個單位即p -1 等效於 p + T - 1
,我們要等到此時的位置,再去餘,(P+T-1)%T。
對於情況一、二。可以歸納為(P+T+d)%T,當為順時針是d取1,否則-1.