【算法】数据结构与算法分析学习笔记——第三章习题选做Josephus问题

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)

感受一下作者的脑洞。。。


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值