【算法】约瑟夫问题--环形单链表实现

7 篇文章 0 订阅
1.约瑟夫问题
  • 又称为约瑟夫环,丢手绢问题等。
  • 来历:

据说著名犹太历史学家 Josephus有过以下的故事:在罗马人占领乔塔帕特后,39 个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。然而Josephus 和他的朋友并不想遵从。首先从一个人开始,越过k-2个人(因为第一个人已经被越过),并杀掉第k个人。接着,再越过k-1个人,并杀掉第k个人。这个过程沿着圆圈一直进行,直到最终只剩下一个人留下,这个人就可以继续活着。问题是,给定了和,一开始要站在什么地方才能避免被处决?Josephus要他的朋友先假装遵从,他将朋友与自己安排在第16个与第31个位置,于是逃过了这场死亡游戏。

2.环形单链表实现
  • Demo:
/**
 * 约瑟夫问题--环形单链表实现
 *
 * @author wangjie
 * @version V1.0
 * @date 2019/12/27
 */
public class JosepfuDemo {

    public static void main(String[] args) {
        CircleSingleLinkedList circleSingleLinkedList = new CircleSingleLinkedList(41);
        circleSingleLinkedList.show();
        circleSingleLinkedList.start(1,3);
        circleSingleLinkedList.show();
    }

}

/**
 * 环形单链表
 *
 * @author wangjie
 * @version V1.0
 * @date 2019/12/27
 */
@Slf4j
class CircleSingleLinkedList{

    /**
     * 头结点
     */
    private Node head;

    /**
     * 节点数
     */
    private int num;
    /**
     * 构建环形链表
     * @param num
     */
    public CircleSingleLinkedList(int num){

        if(1 > num ){
            log.info("【环形链表初始值不能小于1】");
            return;
        }

        this.num = num;

        Node pointer = null;

        for(int i = 1;i <= num;i++){
           Node node = new Node(i);
           if (1 == i){
               head = node;
               pointer = node;
               pointer.next = node;
           }else{
               pointer.next = node;
               node.next = head;
               pointer = node;
           }
        }

    }

    /**
     * 遍历
     */
    public void show(){
        log.info("-------------------------------开始遍历--------------------------------");
        if(null == head){
            log.info("【环形链表为空】");
            return;
        }
        Node pointer = head;
        do{
            log.info("节点编号:{}",pointer.getNo());
            pointer = pointer.next;
        } while (pointer != head);
        log.info("-------------------------------遍历完成--------------------------------");
    }

    /**
     * 开始游戏
     * @param start 从第几个开始数
     * @param no 数多少
     */
    public void start(int start,int no){

        if(null == head || start > num){
            log.info("【参数有误!】");
            return;
        }
        log.info("--------------开始游戏,总人数{},从第{}人开始数,数到{}的人出局------------",num,start,no);
        Node help = head;
        Node pointer = head;
        while (help.next != head){
            help = help.next;
        }
        //头结点置为空
        head = null;
        for (int i = 1;i < start;i++){
            pointer = pointer.next;
            help = help.next;
        }
        while (pointer != help){
            for (int i = 1;i < no;i++){
                pointer = pointer.next;
                help = help.next;
            }
            log.info("{}号出局",pointer.getNo());
            pointer = pointer.next;
            help.next =pointer;
        }
        log.info("-------------------------------游戏结束--------------------------------");
        log.info("{}号胜出",pointer.getNo());
    }
}
/**
 * 链表结点
 *
 * @author wangjie
 * @version V1.0
 * @date 2019/12/27
 */
@Setter
@Getter
class Node{
    /**
     * 编号
     */
    private int no;
    /**
     * 指向下一个结点
     */
    public Node next;

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

}


  • 运行结果:
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - -------------------------------开始遍历--------------------------------
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 节点编号:1
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 节点编号:2
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 节点编号:3
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 节点编号:4
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 节点编号:5
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 节点编号:6
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 节点编号:7
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 节点编号:8
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 节点编号:9
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 节点编号:10
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 节点编号:11
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 节点编号:12
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 节点编号:13
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 节点编号:14
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 节点编号:15
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 节点编号:16
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 节点编号:17
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 节点编号:18
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 节点编号:19
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 节点编号:20
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 节点编号:21
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 节点编号:22
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 节点编号:23
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 节点编号:24
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 节点编号:25
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 节点编号:26
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 节点编号:27
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 节点编号:28
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 节点编号:29
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 节点编号:30
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 节点编号:31
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 节点编号:32
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 节点编号:33
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 节点编号:34
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 节点编号:35
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 节点编号:36
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 节点编号:37
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 节点编号:38
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 节点编号:39
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 节点编号:40
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 节点编号:41
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - -------------------------------遍历完成--------------------------------
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - --------------开始游戏,总人数41,从第1人开始数,数到3的人出局------------
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 3号出局
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 6号出局
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 9号出局
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 12号出局
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 15号出局
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 18号出局
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 21号出局
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 24号出局
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 27号出局
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 30号出局
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 33号出局
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 36号出局
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 39号出局
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 1号出局
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 5号出局
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 10号出局
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 14号出局
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 19号出局
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 23号出局
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 28号出局
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 32号出局
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 37号出局
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 41号出局
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 7号出局
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 13号出局
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 20号出局
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 26号出局
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 34号出局
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 40号出局
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 8号出局
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 17号出局
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 29号出局
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 38号出局
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 11号出局
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 25号出局
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 2号出局
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 22号出局
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 4号出局
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 35号出局
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 16号出局
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - -------------------------------游戏结束--------------------------------
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 31号胜出
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - -------------------------------开始遍历--------------------------------
[main] INFO com.data.algorithm.Josephus.CircleSingleLinkedList - 【环形链表为空】

【完】
注:文章内所有测试用例源码:https://gitee.com/wjie2018/java-data-structure-and-algorithm.git

约瑟夫问题全集 據說著名猶太歷史學家 Josephus有過以下的故事:在羅馬人佔領喬塔帕特後,39 個猶太人與Josephus及他的朋友躲到一個洞中,39個猶太人決定寧願死也不要被敵人到,於是決定了一個自殺方式,41個人排成一個圓圈,由第1個人開始報數,每報數到第3人該人就必須自殺,然後再由下一個重新報數,直到所有人都自殺身亡為止。 然而Josephus 和他的朋友並不想遵從,Josephus要他的朋友先假裝遵從,他將朋友與自己安排在第16個與第31個位置,於是逃過了這場死亡遊戲。 約瑟夫問題可用代數分析來求解,將這個問題擴大好了,假設現在您與m個朋友不幸參與了這個遊戲,您要如何保護您與您的朋友?只要畫兩個圓圈就可以讓自己與朋友免於死亡遊戲,這兩個圓圈內圈是排列順序,而外圈是自殺順序,如下圖所示: 使用程式來求解的話,只要將陣列當作環狀來處理就可以了,在陣列中由計數1開始,每找到三個無資料區就填入一個計數,直而計數達41為止,然後將陣列由索引1開始列出,就可以得知每個位置的自殺順序,這就是約瑟夫排列,41個人而報數3的約琴夫排列如下所示: 14 36 1 38 15 2 24 30 3 16 34 4 25 17 5 40 31 6 18 26 7 37 19 8 35 27 9 20 32 10 41 21 11 28 39 12 22 33 13 29 23 由上可知,最後一個自殺的是在第31個位置,而倒數第二個自殺的要排在第16個位置,之前的人都死光了,所以他們也就不知道約琴夫與他的朋友並沒有遵守遊戲規則了。 c #include <stdio.h> #include <stdlib.h> #define N 41 #define M 3 int main(void) { int man[N] = {0}; int count = 1; int i = 0, pos = -1; int alive = 0; while(count <= N) { do { pos = (pos+1) % N; // 環狀處理 if(man[pos] == 0) i++; if(i == M) { // 報數為3了 i = 0; break; } } while(1); man[pos] = count; count++; } printf(\"\\n約琴夫排列:\"); for(i = 0; i < N; i++) printf(\"%d \", man[i]); printf(\"\\n\\n您想要救多少人?\"); scanf(\"%d\", &alive); printf(\"\\nL表示這%d人要放的位置:\\n\", alive); for(i = 0; i < N; i++) { if(man[i] > alive) printf(\"D\"); else printf(\"L\"); if((i+1) % 5 == 0) printf(\" \"); } p rintf(\"\\n\"); return 0; } java public class Josephus { public static int[] arrayOfJosephus( int number, int per) { int[] man = new int[number]; for(int count = 1, i = 0, pos = -1; count <= number; count++) { do { pos = (pos+1) % number; // 環狀處理 if(man[pos] == 0) i++; i f(i == per) { // 報數為3了 i = 0; break; } } while(true); man[pos] = count; } return man; } public static void main(String[] args) { int[] man = Josephus.arrayOfJosephus(41, 3); int alive = 3; System.out.println(\"約琴夫排列:\"); for(int i = 0; i < 41; i++) System.out.print(man[i] + \" \"); System.out.println(\"\\nL表示3個存活的人要放的位置:\"); for(int i = 0; i < 41; i++) { if(man[i] > alive) System.out.print(\"D\"); else System.out.print(\"L\"); if((i+1) % 5 == 0) System.out.print(\" \"); } System.out.println(); }}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值