约瑟夫环问题--多解

1.概念描述

**约瑟夫环:**已知n个人围成一圈,从编号为k的人开始报数,凡报数为m的人离开圈并从下一个人从1开始数,数到m的那个人再次出圈,反复循环直到圈里只剩下一个人结束。

2.实战题目

这里引入一个之前做过的一道题目:

7-28 猴子选大王 (20分)

一群猴子要选新猴王。新猴王的选择方法是:让N只候选猴子围成一圈,从某位置起顺序编号为1~N号。从第1号开始报数,每轮从1报到3,凡报到3的猴子即退出圈子,接着又从紧邻的下一只猴子开始同样的报数。如此不断循环,最后剩下的一只猴子就选为猴王。请问是原来第几号猴子当选猴王?

输入格式:
输入在一行中给一个正整数N(≤1000)。

输出格式:
在一行中输出当选猴王的编号。

输入样例:
11
输出样例:
7

解法一:数组

#include<stdio.h>

int main()
{
	
	int i=0,t=0;//i表示循环,t为中间量。
	int N=0;//N表示猴子数量
	int count=0;//表示出圈的猴子数量 
	 
	scanf("%d",&N);
	int arr[N];//对数组进行统一的初始化,以便后面计算 
	for(i=0;i<N;i++)
	{
		arr[i]=0;
	}
	while(count<N-1)//当圈里猴子只有一个时不再执行代码
	{
		for(i=0;i<N;i++)
		{
			if(N!=1&&arr[i]==0)//判断是否满足条件
			{
				t++;
				if(t%3==0)//这是满足出圈条件的猴子
				{
					t=0;
					arr[i]=1;//让这个猴子出圈
					count++;
				}
			}
			if(count==N-1)break;
		}
	}
	
	//输出结果 
	for(i=0;i<N;i++)
	{
		if(arr[i]==0)//猴王
		{
			printf("%d\n",i+1);
		}
	}
	
	return 0;
}

上面写的代码为了便于理解并未优化,如有问题请及时指正,感谢大佬。

解法二:循环链表

下面展示一些 内联代码片

// A code block
var foo = 'bar';
// An highlighted block
#include <stdio.h>
#include <stdlib.h>

//声明链表节点 
typedef struct node 
{
    int number;//存储猴子的位号 
    struct node *next;//定义结构体指针,指向下一个节点
}Node;

/*创建链表节点的函数*/ 
Node* CreatNode(int x) 
{
    Node *p;
    p = (Node*)malloc(sizeof(Node));
    p->number = x;//给猴子的位号赋值 
    p->next = NULL;
    return p;
}

//创建环形链表,存放整数1到n
Node* CreatJoseph(int n) 
{
    Node *head,*p,*q;
    int i;
    for(i = 1;  i <= n; i++)//使用循环创建链表节点 
    {
        p = CreatNode(i); //创建一个链表节点,给number赋值 
        if(i == 1)//如果是头结点
            head = p;
        else//不是头结点,则指向下一个节点
            q->next = p;//这里的q->next是上一个节点的地址 
            q = p;
    }
    q->next = head;//末尾节点指向头结点,构成循环链表
    return head;
}

//开始进行运算 
void RunJoseph(int n) 
{
    Node *p,*q;
    p = CreatJoseph(n);//创建循环链表
    int i;
    while(p->next != p)//循环条件,当前链表数目大于1
    {
        for(i = 1; i <2; i++)//开始计数
        {
            p = p->next;//p表示第二只猴子 
        }
        //第3个人出圈 
        q = p->next;//q表示第三只猴子 
        p->next = q->next;//q指向的下一个是第四只猴子 
        p = p->next;//下一次从第四只猴子开始 
        free(q);//把第三只猴子踢出链表。 
    }
    //这里的for循环这样写的原因是,地址操作。 
    printf("%d",p->number);//输出猴子之王。 
}

int main()
{
    int n;
    scanf("%d",&n);
    RunJoseph(n);
    return 0;
}

解法三:函数递归()
思路:推导出递归公式即可
-------------------后续再敲这个代码吧,递归人脑袋大。。。

解法四:迭代代码
思路:与函数递归相似,使用for循环搞出来。
下面展示一些 内联代码片

// A code block
var foo = 'bar';
// An highlighted block
#include <stdio.h>
int main()
{
    int m,i,s=0;
    scanf("%d",&m);
    for(i=1 ; i<=m ; i++)
       s = (s+3) % i ;
     printf("%d\n",s+1);
    return 0 ;
}

3.总结

额。。。。。。
希望有错误的地方大佬及时指出,我及时改过来,嘿嘿。

题目: 每个人手里有个密码。开始给定一个正数m,做为报数上限,从某个人开始循环报数,报到m的人出列;再以该出列的人手中的密码为报数上限,依次报数。打印出列的人的序号的先后顺序。 一. 需求分析 1. 本演示程序中,人数n应为任意的,首先应输入一个值赋给初始报数上限m,程序应能自动保存出列人的序号和将出列的人所持的密码赋给m,再次作为报数上限,如此循环,直至所有人都出列为止。 2. 演示程序以用户和计算机的对话方式执行,即在计算机终端上显示“提示信息”之后,由用户在键盘上输入相应数据(即每个人所持的密码),每个人的序号由程序自动分配。 3. 程序执行的命令包括: (1)构造链表;(2)输入数据;(3)执行报数,储存出列人的序号,删除出列人的信息以及把出列人的密码赋给m;(4)结束。 4. 测试数据 (1)m=20,n=7,7个人的密码依次为:3,1,7,2,4,8,4,首先m值为6,则这正确的出列顺序为6,1,4,7,2,3,5。 确的出列顺序为6,1,4,7,2,3,5。 二. 概要设计 为了实现上述操作,应以单向循环链表为存储结构。 1. 基本操作: code( ) 操作结果:构造空链表,若成功就初始化每个人的相关信息 code( ) 初始条件:线性链表存在 操作结果:释放指向出列的人的结点,并重新报数 2. 本程序包含三个模块: (1) 主程序模块; (2) 构造链表并输入每个人信息模块; (3) 释放结点模块;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值