poj 2244 Eeny Meeny Moo 约瑟夫环

题目大意:有n个城市编号1,2,3,...,n。第1个城市开始网络会断,然后向后数m个,数到的城市会断网,然后继续数,数到n时从1接上数,之前断网的城市忽略,让你求第2个城市最后断网,m的最小值。

解题思路:约瑟夫环,枚举m,求最小m。

约瑟夫环的介绍看这个:http://blog.csdn.net/wuzhekai1985/article/details/6628491讲的很详细。

这里再复述下,自己也加深下印象。。。假如n个数环编号为0,1,2,...,n-1.

跨度为m,那么第一次删除的号码为 (m - 1) % n;

那么下一次的数的个数为n-1,假如n - 1个数环开始数的编号为k

那么做以下映射

k         -----> 0

k+1    ----->  1

k+2   ------>   2

。。。。

k - 2  -------> n - 1

若n - 1个数的数环剩余的最后一个数为 x 时, 把x 逆推映射到数环是n个数的情况。

根据上面的映射,n - 1环的每个数加上k 然后对 n取余能进行逆映射。那么n个数的数环的剩余编号为 (x + k ) % n;

k 由上得为 m % n,那么(x + m % n) % n => ( x % n + (m  % n) % n ) % n => ( x % n + m % n) % n => (x + m) % n;

同理,若n - 2个数的数环剩余最后一个数为y时, 开始的编号为z时,

z        -------->  0

z + 1  --------> 1

z + 2  -------->  2

......

z - 2 ---------> n - 2

z = m % (n - 1)

n - 1个数的剩余编号为(y + z) % n - 1 ===========> (y + m) % n - 1;

所以可以得出递推式

f[1] = 0

for(int i = 2;  i <= n; i++)

f[i] = (f[i-1] + m) % i


这里不管如何是从1就开始删除,那么n个数就成为了n - 1个数,

求n - 1个数的约瑟夫环,2编号映射成为0, 后面每个城市编号都减2

转换成为0~n-1个编号,求最小m,使得剩下最后一个是0

#include <iostream>
#include <cstdio>

using namespace std;

const int maxn = 151;
int result[maxn];
int main()
{
	
	result[0] = 0; result[1] = 0;
	result[2] = 1;
	for(int i = 3; i < maxn; i++)// 先把不同的n对应的m都求出来。
	{
		int m = 1;
		while(true)
		{
			int s = 0;
			for(int k = 2; k < i; k++)
				s = (s + m) % k;
			if(s == 0)
			{
				result[i] = m;
				break;
			}
			m++;
		}
	}
	int n;
	while(true)
	{
		scanf("%d", &n);
		if(0 == n)
			break;
		printf("%d\n", result[n]);
	}
	
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值