约瑟夫环问题

约瑟夫环(约瑟夫问题)是一个数学的应用问题:已知n个人(以编号1,2,3…n分别表示)围坐在一张圆桌周围。从编号为k的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列;依此规律重复下去,直到圆桌周围的人全部出列。通常解决这类问题时我们把编号从0~n-1,最后结果+1即为原问题的解。

数组方式

假设下标从0开始,0,1,2 .. m-1共m个人,从1开始报数,报到k则此人从环出退出,问最后剩下的一个人的编号是多少?

现在假设m=10
0 1 2 3 4 5 6 7 8 9 k=3
第一个人出列后的序列为:
0 1 3 4 5 6 7 8 9
即:
3 4 5 6 7 8 9 0 1(*)
我们把该式转化为:
0 1 2 3 4 5 6 7 8 (**)
则你会发现: ((**)+3)%10则转化为(*)式了

也就是说,我们求出9个人中第9次出环的编号,最后进行上面的转换就能得到10个人第10次出环的编号了
设f(m,k,i)为m个人的环,报数为k,第i个人出环的编号,则f(10,3,10)是我们要的结果
当i=1时, f(m, k ,i) = (m+k-1) % m
当i!=1时, f(m, k, i)= ( f(m-1, k, i-1)+k ) % m

Java实现:

public class Test {
    public static void main(String[] args) {
        for (int i = 1; i <= 10; i++){
            System.out.print(fun(10,3,i) + " ");
        }
    }

    public static int fun(int m, int k, int i){
        if (i == 1){
            return (m + k - 1) % m;
        }else{
            return (fun(m - 1, k, i - 1) + k) % m;
        }
    }
}

上述实现将结点的值设为0~n-1,若要变为1~n-1,则打印fun(m, k, i) + 1即可。

Python实现:

def fun(m, k, i):
    if i == 1:
        return (m + k - 1) % m
    else:
        return (fun(m - 1, k, i - 1) + k) % m


for i in range(1, 11):
    print(fun(10, 3, i), end=' ')

C++实现:

#include <iostream>
using namespace std;

int fun(int m, int k, int i);

int main()
{
    for (int i = 1; i <= 10; i++)
    {
        cout<<fun(10, 3, i)<<" "; // 输出数值为[0,9]
        //cout<<fun(10, 3, i) + 1<<" "; // 输出数值为[1,10]
    }
}

int fun(int m, int k, int i)
{
    if (i == 1)
    {
        return (m + k - 1) % m;
    }
    else
    {
        return (fun(m - 1, k, i - 1) + k) % m;
    }
}

链表方式

使用一个循环链表来实现,每次将一个结点移出链表。
Java实现:

class ListNode{
    int val;
    ListNode next;
    ListNode(int x) {val = x;}
}

public class Josephus {
    ListNode head;
    int n;
    Josephus(int x){
        n = x;
        head = new ListNode(1);
        ListNode pre = head;
        ListNode cur = null;
        for (int i = 2; i <= n; i++){
            cur = new ListNode(i);
            pre.next = cur;
            pre = cur;
        }
        cur.next = head;
    }

    public void PerformKilling(int d){
        d = d % n;
        ListNode pre = null;
        ListNode cur = head;
        int count = 1;
        while (count++ <= n){ // while (cur.next != cur)
            int i = 1;
            while (i++ < d){
                pre = cur;
                cur = cur.next;
            }
            System.out.println("Killing: " + cur.val);
            pre.next = cur.next;
            cur = cur.next;
            i = 1;
        }
        //System.out.println("Killing: " + cur.val);
    }
}

Python实现:

class ListNode:
    def __init__(self, x):
        self.val = x
        self.next = None

class Josephus:
    def __init__(self, x):
        self.n = x
        self.head = ListNode(1)
        pre = self.head
        for i in range(2, x + 1):
            cur = ListNode(i)
            pre.next = cur
            pre = cur
        cur.next = self.head

    def performKilling(self, d):
        cur = self.head
        while cur.next != cur:
            for i in range(1, d):
                pre = cur
                cur = cur.next
            print(cur.val, end=' ')
            pre.next = cur.next
            cur = cur.next
        print(cur.val, end=' ')

J = Josephus(10)
J.performKilling(3)

C++实现:

#include <iostream>
using namespace std;

struct ListNode
{
    int val;
    ListNode *next;
    ListNode(int x) : val(x), next(NULL) {}
};

class Josephus
{
public:
    Josephus(int x)
    {
        n = x;
        head = new ListNode(1);
        ListNode *pre = head;
        ListNode *cur;
        for (int i = 2; i <= x; i++)
        {
            cur = new ListNode(i);
            pre->next = cur;
            pre = cur;
        }
        cur->next = head;
    }

    void performKilling(int d)
    {
        d %= n;
        int count = 1;
        ListNode *pre;
        ListNode *cur = head;
        while (count++ <= n)  //while (cur->next != cur)
        {
            for (int i = 1; i < d; i++)
            {
                pre = cur;
                cur = cur->next;
            }
            cout<<cur->val<<" ";
            pre->next = cur->next;
            delete cur;
            cur = pre->next;
        }
        //cout<<cur->val;
        //delete cur;
    }

private:
    ListNode *head;
    int n; //size of the linked list
};

int main()
{
    Josephus *J = new Josephus(10);
    J->performKilling(3);
}

(使用C++时,特别注意的是释放内存
结束条件可以设置为已经打印了n个结点,或者链表中仅有一个结点(继续打印该唯一结点)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值