约瑟夫环:递归算法
假设下标从0开始,0,1,2 .. m-1共m个人,从1开始报数,报到k则此人从环出退出,问最后剩下的一个人的编号是多少?
现在假设m=10
0 1 2 3 4 5 6 7 8 9 k=3
第一个人出列后的序列为:
0 1 3 4 5 6 7 8 9
即:
3 4 5 6 7 8 9 0 1(*)
我们把该式转化为:
0 1 2 3 4 5 6 7 8 (**)
则你会发现: ((**)+3)%10则转化为(*)式了
也就是说,我们求出9个人中第9次出环的编号,最后进行上面的转换就能得到10个人第10次出环的编号了
设f(m,k,i)为m个人的环,报数为k,第i个人出环的编号,则f(10,3,10)是我们要的结果
当i=1时, f(m,k,i) = (m+k-1)%m
当i!=1时, f(m,k,i)= ( f(m-1,k,i-1)+k )%m
所以程序如下:
int fun(int m,int k,inti){if(i==1)return (m+k-1)%m;else
return (fun(m-1,k,i-1)+k)%m;
}int main(int argc, char*argv[])
{for(int i=1;i<=10;i++)
printf("第%2d次出环:%2d\n",i,fun(10,3,i));return 0;
}
第 1次出环: 2
第 2次出环: 5
第 3次出环: 8
第 4次出环: 1
第 5次出环: 6
第 6次出环: 0
第 7次出环: 7
第 8次出环: 4
第 9次出环: 9
第10次出环: 3
数学解(提供思路):
参考C#做法(据说不是很好)
常用算法(C#): 约瑟夫环问题
约瑟夫环问题: 设有n个人围坐在圆桌周围,现从某个位置m(1≤m≤n)上的人开始报数,报数到k的人就站出来。
继续下一个人,即原来的第k+1个位置上的人,又从1开始报数,再报数到k的人站出来。依此重复下去,直到全部的人都站出来为止usingSystem;usingSystem.Collections.Generic;usingSystem.Text;namespaceExJose
{classClassJose {//从第start人开始计数,以alter为单位循环记数出列,总人数为total
public int[] Jose(int total, int start,intalter)
{int j, k = 0;//count数组存储按出列顺序的数据,以当结果返回
int[] count = new int[total + 1];//s数组存储初始数据
int[] s = new int[total + 1];//对数组s赋初值,第一个人序号为0,第二人为1,依此下去
for (int i = 0; i < total; i++)
{
s[i]=i;
}//按出列次序依次存于数组count中
for (int i = total; i >= 2; i--)
{
start= (start + alter - 1) %i;if (start == 0)
start=i;
count[k]=s[start];
k++;for (j = start + 1; j <= i; j++)
s[j- 1] =s[j];
}
count[k]= s[1];//结果返回
returncount;
}static void Main(string[] args)
{
ClassJose e=newClassJose ();int[] a = e.Jose(10,3,4);for (int i = 0; i < a.Length; i++)
{
Console.WriteLine(a[i].ToString ());
}
}
}
}