C语言笔试编程题——类约瑟夫环问题

题目:传说当年花果山一堆猴子要选大王,一堆猴子都有编号,分别是1,2,3,… ,n ,这群猴子(n只)按照1至m的顺序围坐一圈,从第1只开始每隔m只猴子,淘汰k只猴,这样依次下来,直到圈中只剩下最后一只猴子,则该猴子为大王。

此题是类似于约瑟夫环,约瑟夫问题是个有名的问题:N个人围成一圈,从第一个开始报数,第M个将被淘汰掉,最后剩下一个,其余人都将被淘汰。例如N=6,M=5,被杀掉的顺序是:5,4,6,2,3,1。

用循环单链表实现。

#include 
#include 

//创建循环链表类型
typedef struct{
     
    int num;
    struct Looplist *next;
}Looplist;

//根据输入的猴子个数,创建循环链表
Looplist *creat_looplist()
{
     
    Looplist *head=NULL;
    head=(Looplist *)malloc(sizeof(Looplist));
    head->next=head;
    return head;
}

//插入结点
void inset_looplist(Looplist *head,int Date)
{
     
    Looplist *temp=(Looplist *)malloc(sizeof(Looplist));
    temp->num=Date;
    temp->next=head->next;
    head->next=temp;
}

//创建有头结点head的n个结点的单向循环链表
void creat_circle(int n,Looplist *head)
{
     
    int i;
    for(i=n-1;i>=0;i--)
    {
     
        inset_looplist(head,i);
    }
}

//打印链表
void printf_looplist(Looplist *head)
{
     
    Looplist *p=head;
    printf("打印链表\n");
    do
    {
     
        printf("%d\t",p->num);
        p=p->next;
    }while(p!=head);
    printf("\n");
}

//删除头结点
Looplist *delete_looplist_head(Looplist *head)
{
     
    Looplist *p=NULL;

    p=head;
    while(head->next!=p)
    {
     
        head=head->next;
    }
    head->next=p->next;
    free(p);
    return head->next;    //此时的head指针已经不是原来的固定的头指针了,所以在完成循环之后,head已经指向最后一个指针,所以head->next为真正的头地址

         /** \brief
    p=head;
    while(p->next!=head)
    {
        p=p->next;
    }
    head=p;
    return head->next;    //此时的head指针已经不是原来的固定的头指针了,所以在完成循环之后,head已经指向最后一个指针,所以head->next为真正的头地址
      */
}

//按照约瑟夫环实现方法
void yuesefu(int n,int m,int k)
{
     
    //首先创建一个循环链表
    Looplist *temp=NULL,*temp1=NULL,*temp2=NULL,*head=creat_looplist();
    creat_circle(n,head);               //构建环形链表
    head=delete_looplist_head(head);      //删除头结点
    printf_looplist(head);
    temp=head;
    temp1=head;
    temp2=head;
    while(temp1->next!=temp1)
    {
     
        int i;
        for(i=0;i<m-k-1;i++)    //temp1指向该保留的最后一个结点
            temp1=temp1->next;
        for(i=0;i<m;i++)        //temp2指向下一组的第一个结点
            temp2=temp2->next;
        temp1->next=temp2;      //temp1最后一个指向下一组第一个,然后循环
        printf("我看看temp2在哪=%d\n",temp2->num);
        temp1=temp1->next;      //将temp1和temp2都指向下一组第一个,以便重复上面的指令
        printf("看看temp1在哪=%d\n",temp1->num);

       if((temp=temp1->next,temp1==temp->next))    //判断如果只剩两只,根据题意保留前面的
        {
     
            for(i=0;i<m-k-1;i++)
                temp1=temp1->next;
            temp1->next=temp1;
            break;
        }
   }

    printf("Which monkey is the king:%d\n",temp1->num);
    printf_looplist(temp1);
    free(temp2);
    free(temp);
    temp2=NULL;
    temp1=NULL;
}

int main()
{
     
    int n,m,k;
    printf("请分别输入猴子的数量,每次隔几只猴子开始淘汰,每次淘汰猴子的个数:\n");
    scanf("%d %d %d",&n,&m,&k);
    if(n<1 || n>1000000 || k >= m || k <= 0)
	{
     
		printf("输入参数有误\n");
	    return -1;
	}
	else if(n == 1){
     
		printf("Which monkey is the king:%d\n",n-1);
		return 0;
	}
	else
	{
     
        yuesefu(n,m,k);
	}
    return 0;
}

若有不足之处还望大家指正

你可能感兴趣的:(C/C++,约瑟夫问题,编程题,链表)