C 约瑟夫双向生死游戏

C语言 约瑟夫双向生死游戏

项目简介

约瑟夫双向生死游戏是在约瑟夫生者死者游戏的基础上,正向计数后反向计数,然后再正向计数。具体描述如下:30个旅客同乘一条船,因为严重超载,加上风高浪大,危险万分;因此船长告诉乘客,只有将全船一半的旅客投入海中,其余人才能幸免遇难。无奈,大家只得同意这种办法,并议定30个人围成一圈,由第一个人开始,顺时针依次报数,数到第9人,便把他投入大海中,然后从他的下一个人数起,逆时针数到第5人,将他投入大海,然后从他逆时针的下一个人数起,顺时针数到第9人,再将他投入大海,如此循环,直到剩下15个乘客为止。问哪些位置是将被扔下大海的位置。

设计思路

本游戏的数学建模如下:假设n个旅客排成一个环形,依次顺序编号1,2,…,n。从某个指定的第1号开始,沿环计数,数到第m个人就让其出列,然后从第m+1个人反向计数到m-k+1个人,让其出列,然后从m-k个人开始重新正向沿环计数,再数m个人后让其出列,然后再反向数k 个人后让其出列。这个过程一直进行到剩下q个旅客为止。

本游戏的要求用户输入的内容包括:

  1. 旅客的个数,也就是n的值;
  2. 正向离开旅客的间隔数,也就是m的值;
  3. 反向离开旅客的间隔数,也就是k的值;
  4. 所有旅客的序号作为一组数据要求存放在某种数据结构中。

本游戏要求输出的内容是包括

  1. 离开旅客的序号;
  2. 剩余旅客的序号;

实现代码

/*
	采用双向链表的方式实现这一游戏 
*/
#include 			//scanf printf函数; 
#include 			//malloc free函数; 

//定义双链表的结构; 
typedef struct LNode{
	int data;
	struct LNode *next,*front; 
}LNode; 
typedef struct{
	LNode *rear,*prior;		//队头、队尾指针; 
	int size;				//定义队列的长度,用于判断是否为空; 
}LinkLNode;

//初始化双链表;(不带头结点)
void InitLink(LinkLNode &L){
	 L.prior = L.rear = NULL; 
	 L.size = 0; 
}

//插入数据;
void InsertLink(LinkLNode &L,int data){
	LNode *p = (LNode *)malloc(sizeof(LNode));
	p->data = data;
	if (L.rear == NULL)		//判断插入的是否是第一个元素; 
	{
		p->next = p;
		p->front = p;
		L.prior = L.rear = p;
	}else{
		p->next = L.rear->next;
		L.rear->next->front = p;
		p->front = L.rear;
		L.rear->next = p;
		L.rear = p;
	} 
	L.size++;
}

//删除数据结点p;返回删除的下一个结点n; 
LNode *DeleteLink(LinkLNode &L,LNode *p){
	LNode *n = NULL; 
	if (L.size == 0)		//队列空报错; 
		return n;
	if (L.size == 1)		//删除的是最后一个元素;
	{
		L.prior = L.rear =NULL;
		free(p);			//释放指针p的指向; 
		return n;
	}		 
	else if(L.prior->data != p->data){
		/*
		在此程序中,每个指针指向的data数据不一样,可作为判断
		是否是头指针的依据;在此需要保护双向链表的头指针的指向, 
		打印的时候需要头指针,而尾指针已经没有用处,不需要保护; 
		*/ 
		p->front->next = p->next;
		p->next->front = p->front;
	}else{
		L.prior = p->next; 
		p->front->next = p->next;
		p->next->front = p->front;
	} 
	n = p->next;
	free(p);
	L.size--;
	return n;
}

//结点s向前查找m个元素(逆时针)
LNode *GetFront(LNode *s, int m){
	LNode *p;
	for (int j = 0; j < m; j++)
		p = s->front;
	return p;
}
 
//结点s向后查找n个元素(顺时针) 
LNode *GetBehind(LNode *s, int n){
	LNode *p = s;
	for (int j = 0; j < n; j++)
		p = s->next;
	return p;
}
//打印队列;
bool PrintLink(LinkLNode L){
	if (L.size == 0)
		return false;
	LNode *p = L.prior;		//定位链表的头指针指向; 
	for (int j = 0; j < L.size; j++)
	{
		printf("%d and ",p->data);
		p = p->next;
	}
	printf("NULL\n");	
	return true; 
}


int main(){
	LinkLNode people;
	LinkLNode delpeople;
	LNode *p;
	//定义旅客人数、正向离开间隔数、反向离开间隔数、开始人的位置 
	int pnum,fornum,renum,stnum;	
	//初始化两个双向链表;用于存放旅客的情况; 
	InitLink(people);
	InitLink(delpeople);
	printf("Welcome to the game. Now it's begining!\n");
	//判断输入的人数是否有效;之后的代码已省略,可自行添加;
	while (1)
	{
		printf("input the number of people:");
		scanf("%d",&pnum);		
		if (pnum > 0)	 
			break;
	}
	for (int i = 1; i < pnum + 1; i++) 
		InsertLink(people,i);
	printf("input the number of forward departures:");
	scanf("%d",&fornum);
	printf("input the number of reverse departures:");
	scanf("%d",&renum);
	printf("input the number of started people:"); 
	scanf("%d",&stnum); 
	//进行游戏!!!!定位到开始人的位置; 
	p = GetBehind(people.prior,stnum - 1);
	//淘汰一半的人;
	for (int j = 0; j < pnum / 2; j++) 
	{	
		if (j % 2 == 0)			//第一次顺时针; 
			p = GetBehind(p,fornum);
		else
			p = GetFront(p,renum);
		InsertLink(delpeople,p->data);	//将要淘汰的人加入到delpeople链表中; 
		p = DeleteLink(people,p);		//删除指定节点; 
		if (p == NULL)
		{
			printf("An error occurred in a node.");	
			return 1;
		}		
	}
	
	printf("the number of the Survivors is:\n"); 
	PrintLink(people);
	printf("the number of the Leaver is:\n");
	PrintLink(delpeople);
}

最后:

运行之后输入的数据顺序
第一步:输入旅客人数;
第二步:输入顺时针计数的人数;
第三步:输入逆时针计数的人数;
第四步:输入计数人的开始位置;
第五步:分别打印存活的序列号和被淘汰的序列号;

你可能感兴趣的:(C,c语言,数据结构,队列)