3.14Josephus问题可以描述为如下的一个游戏:N个人编号从1到N,围坐成一个圆圈,从1号开始传递一个热土豆,经过M次传递后拿着土豆的人离开圈子,由坐在离开的人的后面的人拿起热土豆继续进行游戏,直到圈子只剩下最后一个人。例如:M=0,N=5,则游戏人依次被清除,5号最后留下;如果M=1,N=5,那么被清除的人的顺序是2,4,1,5,最后剩下的是3号。
这里给出两种实现方法,第一种是最容易想到的,也就是直接程序模拟实现,用数组链表都可以,直接贴代码,是用单循环链表实现的,这种方法的时间复杂度是O(MN)
代码如下:
//Josephus question
#include
#include
#include
struct node
{
int data;
struct node *next;
};
typedef struct node* pnode;
//new a node, which the data is i, and insert it after p, then return the address of the node
pnode CircleQueue_new (pnode tp, void* pdata)
{
pnode newnode;
newnode = malloc (sizeof (struct node));
newnode->data = * ((int*)pdata);
if (tp == NULL)
{
newnode->next = newnode;
}
else
{
newnode->next = tp->next;
tp->next = newnode;
}
return newnode;
}
//delete a node, and return the node's next node
pnode CircleQueue_de (pnode tp, pnode tpp)
{
tpp->next = tp->next;
free (tp);
return tpp->next;
}
int main ()
{
int n,m;
int i,j;
pnode p = NULL;
pnode header = NULL;
pnode pp = NULL; //pp means previous node of the p
//input the n & m
printf ("please input the number of the people\n");
scanf ("%d", &n);
printf ("please input the legth of the step\n");
scanf ("%d", &m);
//new a circle queue
i=0;
header = CircleQueue_new (p, (void*)&i);
p = header;
i++;
for (; i
next; //p point to the fist node of the circle queue
//simulate the game
for (i=0; i
next; } p = CircleQueue_de (p, pp); } //print the winner printf ("the winner is %d\n", p->data); return 0; }
然后介绍一种递推的方法,我们再回到题目去分析,就使用M=3,N=4的例子吧
我们可以想想,在最后剩下一个人的时候,我们虽然不知道这个人原先的编号,但是我们可以确定他是第0个(也就是说每次出队后都把剩下的重新编号),那么是否可以反推过去,算出他原来的编号呢?
画个图形象一点
每一次出队后,由出队的下一个作为0,很快就可以发现规律,
第一次n=4,3-->0,0(+4)-->1,1(+4)-->2
第二次n=3,0(+3)-->0,1(+3)-->1
第三次n=2,1(+2)-->0
换成通项公式就是f(n-1)=[ f(n) - M ] % n
如果反过来推就是f(n)=[ f(n-1) + M ] % n
代码如下:
#include
#include
int count (int n, int m)
{
if (n == 1)
return 0;
else
return ( count (n-1, m) + m ) % n;
}
int main ()
{
int n,m;
int i;
int num = 0;
printf ("please input the number of the people\n");
scanf ("%d", &n);
printf ("please input the legth of the step\n");
scanf ("%d", &m);
printf ("the winner is %d\n", count (n,m));
return 0;
}
3.22提出支持栈的Push和Pop操作以及第三种操作FindMin的数据结构,其中FindMin返回该数据结构的最小元素 所有操作在最坏的情况下的运行时间都是O(1)
感受一下作者的脑洞。。。