1. 程式人生 > >LA3882(約瑟夫問題及變形)

LA3882(約瑟夫問題及變形)

我相信大家早就瞭解了約瑟夫問題

如小學的  猴子選大王:一堆猴子都有編號,編號是1,2,3 ...m,這群猴子(m個)按照1-m的順序圍坐一圈,從第1開始數,每數到第N個,該猴子就要離開此圈,這樣依次下來,直到圈中只剩下最後一隻猴子,則該猴子為大王。

作為一道相當經典的題,還有一個使其更簡單的變式

題目大意:

N個數排成一圈,第一次刪除m,以後每k個數刪除一次,求最後一被刪除的數(即最後留下是的數,下面用“勝利者”來代指要求的數)

題解:

假設從0開始刪除第k個數,很顯然,第 k mod n個人背踢出,然後剩下的n-1個人組成一個新環,並且勝利者一定在中間)

k k+1 k+2 ... n-2,n-1,0,1,2,... k-2

並且從k開始報0。

我們把他們的編號做一下轉換:

k --> 0

k+1 --> 1

k+2 --> 2

...

k-2 --> n-2

接下來需要將勝利者的序號調整回來,這十分簡單:x'=(x+k) mod n

那麼我們如何在(n-1)個數中尋找勝利者呢?顯而易見,他一定在去掉第k mod n個人的(n-2)人中,再調整為0~n-2,然後不斷遞推

公式:

f[1]=0; f=(f+m) mod i; (i>1) 又因為m<>0,所以答案是ans=(m-k+1+f[n])%n,注意要處理ans<=0的情況(ans=ans+n)

下面是程式碼:


#include<cstdio> 

int main()
{
  int n,m,k,f;
  while(scanf("%d%d%d",&n,&k,&m)==3&&n)
  {
  	f=0;
  	for(int i=2;i<=n;i++)f=(f+k)%i;
  	f=(m-k+1+f)%n;
  	if(f<=0)f+=n;
  	printf("%d\n",f);
  }
}

因為不需要儲存f,所以不需陣列f[n],這樣可以大大的減小記憶體