数据结构(ZKNU OJ) 猴子选大王(循环链表解法)

Description

有m个猴子围成一圈,按顺时针编号,分别为1到m。现打算从中选出一个大王。经过协商,决定选大王的规则如下:从第一个开始顺时针报数,报到n的猴子出圈,紧接着从下一个又从1顺时针循环报数,...,如此下去,最后剩下来的就是大王。

Input

第一行是一个正整数T表示测试数据的组数。下面共有T行,每行两个整数m和n,用一个空格隔开,分别表示猴子的个数和报数n。1≤m≤100,1≤n≤200。

Output

每组数据对应有一个输出,表示大王的编号。

Sample Input

1
3 2

Sample Output

3

显而易见,这又是经典的约瑟夫环问题。

关于约瑟夫环有很多解法,网上也有很多优秀的解法代码,以下只是个人解题理解,仅供参考。

循环链表--解决约瑟夫环问题

        *首先一个需要注意的地方,建立链表,按照老师上课讲的方法,头节点后边跟数据虚拟节点,然后才跟数据元素节点

           

                         *图片来自于王洪峰老师课件

但是考虑到两个地方,一是本题所用链表头节点不需要存放关于链表的信息,所以可以用数据节点当作头节点,不需要定义专门的头节点结构类型;二是本解法是循环链表,为了节约时间(主要是我懒!- -)。所以,我直接采用虚拟数据节点当作头节点,未专门定义头节点数据类型,看代码时候需注意。

解题思路:

       1.创建链表,对链表各个节点编号,读入数据完成后,尾节点指针域指向第一个数据节点,构成循环链表

       2.遍历链表并计数,计数到n-1的时候,删除下一个节点,计数清零。如此循环,直到只剩一个节点(也就是两个相邻节点数据相等时),跳出循环。

       3.指针带回最后所剩的数据,打印输出。

整个思路很简单,关键是循环链表的构建不能出错!

具体实现代码及详细注释:

#include<stdio.h>
#include<malloc.h>
typedef struct LDataNode
{
	int number;
	struct LDataNode *next;
}LDataNode,*LinkList;
int InitList(LinkList *head);
int ListCreate(LinkList *head,int n);
int ListDelete(LinkList *head,int *flag);  
//初始化 
int InitList(LinkList *head)
{
	*head = (LinkList)malloc(sizeof(LDataNode));
	if(*head == NULL)
	{
		return -1;   //内存分配失败 
	}		
	(*head)->next = NULL;
	return 0;
}
//读入数据 
int ListCreate(LinkList *head,int n)
{
	//尾插法原理 
	LinkList rear=(LinkList)malloc(sizeof(LDataNode));
	rear=*head;
	for(int i=1;i<=n;i++)//编号进入链表 
	{
		LinkList p=(LinkList)malloc(sizeof(LDataNode));
		p->next=rear->next;
		p->number=i;
		rear->next=p;
		rear=p;
	}
	rear->next=(*head)->next;//这一步是重点,构建循环!! 
}
//删除节点 
int ListDelete(LinkList *p,int *flag)//flag带回所删除的数据,备份 
{
	if((*p)->next->number==(*p)->number)//两个相邻节点数据相同 
	{
		*flag=(*p)->number;//说明只剩一个节点了 
		return 1;
	}
	//删除操作 
	*flag=(*p)->next->number;		
	LDataNode *q = (*p)->next->next;
    (*p)->next=q;
	return 0;
}
int main()
{
	int T,m,n;
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d%d",&m,&n);
		LinkList head;
		InitList(&head);
		ListCreate(&head,m);
		LDataNode *p=(LDataNode *)malloc(sizeof(LDataNode));
		p=head;
		int count=0,x;
		while(1)
		{
			p=p->next;
			count++;//计数 
			if(count==n-1)
			{
				count=0;
				//删除第n个节点 
				int flag=ListDelete(&p,&x);
				if(flag)
				{
					break;
				}
			}
		}
		printf("%d\n",x);
	} 
} 

猜你喜欢

转载自blog.csdn.net/holly_Z_P_F/article/details/79805753