首页 > 代码库 > Poj 3517 And Then There Was One Joseph环问题

Poj 3517 And Then There Was One Joseph环问题

一个基本上纯粹的Joseph环问题,不过第一步额外多了一个m。

那么可以利用递推得出公式:

Win(n) 代表有n个人的时候胜出的号码,

那么Win(n)必然等于Win(n-1),当去掉下一个出队列的人的时候。

下一个出队列的人是谁呢? 如果模是mod的话,那么下一个出队号码计算为:

Lose(n) = mod % n;

if (Lose(n) == 0) Lose(n) = n;

这样得到公式:

Win(n) - Lose(n)  = Win(n-1);

Win(n) = Win(n-1) + Lose(n);

但是注意人数只有n个了,所以要取模:

Win(n) = (Win(n-1) + Lose(n)) % n;

if (Win(n) == 0) Win(n) = n;

然后因为最后要剩下一个人,那么最后一个人为Win(1) = 1;


但是如果写一般的递归公式,那么就会导致栈溢出的,所以要逆过来,从只有1个人的时候推起,推到第n


这样够清晰了吧,这你都不明白我就没办法了。

作者:靖心 http://blog.csdn.net/kenden23/article/details/30050425

最后得到AC代码:

#include <cstdio>
int main()
{
	int n, k, m;
	while (scanf("%d %d %d", &n, &k, &m) && m)
	{
		int winN_1 = 1, winN = 0;
		for (int i = 2; i < n; i++)
		{
			int t = k % i;
			if (t == 0) t = k;

			winN = (winN_1 + t) % i;
			if (winN == 0) winN = i;

			winN_1 = winN;
		}
		int t = m % n;
		if (t == 0) t = m;

		winN = (winN_1 + t) % n;
		if (winN == 0) winN = n;

		printf("%d\n", winN);
	}
	return 0;
}


当然我们可以简化上面程序,思路是一样的,不过根据模的特性简化一下罢了:

网上一般是下面这样的程序,不过他们的推导,我个人觉得较难懂,所以有上面我自己的推导和程序。

我的推导是把这样的模简化隔离出来,我个人觉得会清晰很多。

所以如果你看了网上类似的下面程序,觉得糊里糊涂的话,建议可以参考我上面的程序。

#include <cstdio>
int main()
{
	int n,k,m;
	while(scanf("%d%d%d",&n,&k,&m) && n)
	{
		int winN = 0, winN_1 = 0;
		for(int i = 2; i < n; i++)
		{
			winN = (winN_1 + k) % i;
			winN_1 = winN;
		}
		winN = (winN_1 + m)%n;
		printf("%d\n", winN+1);
	}
	return 0;
}