1. 程式人生 > >poj 1012 Joseph(約瑟夫環求每次出圈人的序號)

poj 1012 Joseph(約瑟夫環求每次出圈人的序號)

有k個好人和k個壞人,前k個是好人後k個是壞人。模擬約瑟夫環,每次數到m的數要被殺死,然後他後面的人從1開始報數。重複這個過程。要求輸出最小的m,使得前k個被殺死的人都是壞人。

因為k比較小,我們可以列舉m,列舉到某個m滿足前k個出圈人的序號都大於等於k,那麼m就是所求。

以k=3為例,6個人的編號為0 1 2 3 4 5 ,好人的序號為0~k-1,壞人的序號是 k~2*k-1。

首先推出每次出圈的人在當前序列中的序號,用ans[i]表示第i個出圈的人的序號。

若m = 5,

那麼ans[1] = 4,ans[2] = 3,根據這兩個數我們可以推出ans[i] = (ans[i-1] + m-1)%(n-i+1),其中ans[0] = 0。注意這裡的ans[i]是在前一輪殺死一個人後重新編號。

#include <stdio.h>
#include <iostream>
#include <map>
#include <set>
#include <list>
#include <stack>
#include <vector>
#include <math.h>
#include <string.h>
#include <queue>
#include <string>
#include <stdlib.h>
#include <algorithm>
#define LL long long
#define _LL __int64
#define eps 1e-12
#define PI acos(-1.0)
#define C 240
#define S 20
using namespace std;

int f[30];
int ans[30];

int main()
{
	int k;
	memset(ans,-1,sizeof(ans));
	while(~scanf("%d",&k))
	{
		if(k == 0) break;
		if(ans[k] != -1) //如果已經計算過,儲存下來不再重複計算
		{
			printf("%d\n",ans[k]);
			continue;
		}
		int n = k*2; //總人數

		int m = 1; //從1列舉
		f[0] = 0;
		for(int i = 1; i <= k; i++) //在m下求出前k個出圈的人的編號
		{
			f[i] = (f[i-1]+m-1)%(n-i+1);
			if(f[i] < k) //好人被殺死,m不符,好人的編號一直是0~k-1
			{
				i = 0;
				m++;
			}
		}
		ans[k] = m;
		printf("%d\n",ans[k]);
	}
    return 0;
}