约瑟夫环问题
问题:n个人编号1~n,报数报到m的出队,问最后一个人是谁(队列成环)
数学递推:复杂度O(n)
Josephus(int n,int m)
{
int s = 0;
for (int i = 2; i <= n; i++)
{
s = (s + m) % i;
}
return s;
}
——稍加优化——
注意:做ACM题时,经常遇到取模操作, 取模运算是算术操作中中最慢的(在当前的计算机硬件中基本都是这样)。
1 对2的幂取模(2^k),实际等同于和(2^k – 1)进行“位与”操作
例如对8取模,因为计算机内部是二进制表示,所以可以对二进制位进行位与操作。
2 经常有一些递推式,是加和后求模关系,这时可以利用有限范围的特性, 将求模转换为加减法
摘自取模速度优化
所以从这一点入手,可以优化为
Josephus(int n,int m)
{
int s = 0;
for (int i = 2; i <= n; i++)
{
if (m >= i) s = s + m % i;
else s = s + m;
if (s >= i) s -= i;
}
return s;
}
——更加优化——
// 这里其实并不是很懂,附上代码
int Josephus(int n,int m, int k) //人数、步长、起始报数位置
{
if (m == 1)
{
k = k == 1? n : (k + n - 1) % n;
}
else
{
for (int i = 1; i <= n; i++)
{
if (k + m < i)
{
int x = (i - k + 1) / (m - 1) - 1;
if (i + x < n)
{
i = i + x;
k = (k + m * x);
}
else
{
k = k + m * (n - i);
i = n;
}
}
k = (k + m - 1) % i + 1;
}
}
return k;
}