有n个囚犯站成一个圆圈,准备处决。首先从一个人开始,越过k-2个人(因为第一个人已经被越过),并杀掉第k个人。接着,再越过k-1个人,并杀掉第k个人。这个过程沿着圆圈一直进行,直到最终只剩下一个人留下,这个人就可以继续活着。问题是,给定了n和k,一开始要站在什么地方才能避免被处决?
1.循环链表
struct Person
{
int num;
Person *next;
Person(int x):num(x),next(NULL){}
};
int Josephus(int n,int k)
{
//构造循环链表
//尾插法,p指向头,q指向尾
Person *p=new Person(0),*q=p,*r=NULL;
for(int i=1;i<n;++i)
{
r=new Person(i);
q->next=r;
q=r;
}
q->next=p;
//删除结点
while(n-->1)
{
for(int i=1;i<k;++i)p=p->next;
q=p->next;
p->num=q->num;
p->next=q->next;
delete q;
}
int last=p->num;
delete p;
return last;
}
2.动态规划
考虑<环长为i时的编号>和<环长为i-1时的编号>之间的关系
环长为i时的编号0 .. i - 1,去掉k-1,从k开始得到k .. i - 1, 0 .. k - 2
对应环长为i - 1时的编号0 .. i - 1 - k, i - k .. i - 2
f(i)表示环长为i时最后剩下的编号
所以f(i) = [f(i -1) + k] % i,f(1) = 0
int Josephus(int n,int k)
{
int last=0;
for(int i=2;i<=n;++i)last=(last+k)%i;
return last;
}