约瑟夫问题的几种解决方法

约瑟夫问题的几种解决方法,第1张

        约瑟夫问题(有时也称为约瑟夫斯置换,是一个出现在计算机科学和数学中的问题。在计算机编程的算法中,类似问题又称为约瑟夫环。又称"丢手绢问题".)。

编号为1.2.3…….n的n个人按顺时针方向围坐一圈,开始任意选一个整数作为报数,从第一个人开始顺时针自1开始顺序报数,报到m时停止报数。报m的人出列,从出列的下一个人开始报数,报到m的人再退出,如此下去直到剩下一个人为止。

1.第一种单向的环形链表解决 首先将链表中的节点Boy创建出来
/**
 * 创建Boy节点
 * 
 * @author Administrator
 */
class Boy {
	private int no;
	private Boy next;

	public Boy(int no) {
		this.no = no;
	}

	public int getNo() {
		return no;
	}

	public void setNo(int no) {
		this.no = no;
	}

	public Boy getNext() {
		return next;
	}

	public void setNext(Boy next) {
		this.next = next;
	}

}
单向环形链表的添加方法
// 添加小孩 构成环形链表
	public void addBoy(int nums) {
		// 添加数目小于1时,不让游戏开始
		if (nums < 1) {
			System.out.println("nums的值不正确");
		}
		// 创建curBoy辅助变量 帮助构建环形
		Boy curBoy = null;
		// 使用for创建环形链表
		// 循环创建boy 创建的是第一个就让头的下一个指向自己构成环形
		for (int i = 1; i <= nums; i++) {
			Boy boy = new Boy(i);
			if (i == 1) {
				first = boy;
				first.setNext(first);
				// 用辅助变量一个一个走
				curBoy = first;
			} else {
				// 加入的是第二个就让辅助变量的下一个指向新增变量
				curBoy.setNext(boy);
				// 新增变量的下一个指向头
				boy.setNext(first);
				// 让辅助变量后移 一直当最后一个节点
				curBoy = boy;
			}
		}
	}
单向环形链表的遍历方法
/**
	 * 遍历环形链表
	 */
	public void showBoy() {
		// 判断链表是否为空
		if (first == null) {
			System.out.println("没有任何小孩");
			return;
		}
		// 创建curBoy辅助变量 帮助构建环形
		Boy curBoy = first;
		while (true) {
			System.out.println("输出小孩的编号" + curBoy.getNo());
			if (curBoy.getNext() == first) {
				// 说明链表遍历完了
				System.out.println("遍历完毕");
				break;
			}
			// curBoy后移
			curBoy = curBoy.getNext();
		}
	}
然后创建单向链表的出圈方法
class CircleSingleLinkedList {
	// 创建一个first节点 不赋值
	private Boy first = null;

	/**
	 * 出圈
	 * 根据用户的输入 表示小孩  一共几个  从哪个小孩数数,数几下
	 * @param nums
	 */
	public void countBoy(int nums, int firstNum, int count) {
		
		//起始位置不能大于小孩个数  链表为空也不行  开始位置不能小于1
		if (nums < firstNum ||  firstNum < 1) {
			System.out.println("参数不合理");
			return;
		}
		addBoy(nums);
		//看创建的链表是否成功
		if(first==null) {
			System.out.println("链表为空");
		}
		// 创建辅助指针 并通过循环让他指向环形链表的最后一个节点
		Boy helper = first;
		while(true) {
			if(helper.getNext()==first) {
				break;
			}
			helper=helper.getNext();
		}
		// 报数时first要移动到开始报数时的位置
		for (int i = 1; i < firstNum; i++) {
			first=first.getNext();
			helper=helper.getNext();
		}
		// 循环遍历
		while (true) {
			//假如辅助变量是first  说明只剩下一个节点
			if (helper == first) {
				System.out.println("说明圈中只有一个节点");
				break;
			}
			//开始数数  for循环结束 first的位置就是要删除的节点的位置
			for(int j = 1;j

2.第二种列表解决约瑟夫问题的思路

	//big是一共有多少个孩子  order是从哪个孩子开始  nums是隔几个开始
	public static void orderByInput(int big,int order,int nums){

		
		//创建了一个数组
		ArrayList list = new ArrayList<>();
		//将每个学生加入到数组中
		for(int i =1;i<=big;i++){
			System.out.println("加入"+i+"个周硕");
			list.add(i);
		}
		//当列表中的数只有一个的时候将他打印出来
		while(true){
			if(list.size()==1){
				System.out.println("只剩下"+list.get(0)+"个周硕");
				break;
			}
			//求出要取出的孩子 从哪个孩子开始加上隔的数 就是下一个要去除的孩子
			//加上列表的元素数量是怕order+nums-1是负数  取模是为了数值超出列表长度
			Integer kid = list.get((order+nums-1+list.size())%list.size());
			//输出要移除的这个孩子的编号
			System.out.println("移除"+kid.intValue()+"个周硕");
			//移除这个孩子
			list.remove(kid);
			//让order后移
			order = (order+1+list.size())%list.size();
		}
	}
	public static void main(String[] args) {
		Scanner scanner = new Scanner(System.in);
		
		System.out.println("游戏规则 一共n个小孩 从第m个小孩开始  每次数到 k 就移除这个人 最后只剩下一个人");
		System.out.println("需要多少个人玩");
		int i1 = scanner.nextInt();
		System.out.println("第几个开始 最后剩下谁");
		int i12 = scanner.nextInt();
		System.out.println("最后剩下谁");
		int i13 = scanner.nextInt();
		
		orderByInput(i1,i12,i13);
	}

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/729576.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-27
下一篇 2022-04-27

发表评论

登录后才能评论

评论列表(0条)