每日一题14:数组与链表组合方案下的Josephus问题

愚人节快乐!几天没写程序,今天继续!Josephus问题是说N个人围成一个圈传热土豆,先约定一个数M,当传递了M次的时候拿着土豆的人出局,然后将土豆给出局人的下一个人,游戏继续,直到最后只剩下一个人,求出局人的序列(按出局顺序排列)。
这个问题可以用数组实现,但是需要标记代表出局人的元素,并且没遍历一个元素就要检查该元素是否已被标记为出局,这样程序运行时间必然会变慢。另一种方式是使用一个链表,每次把出局的节点删除掉。这样的解决方案非常直观,只需要关注链表中的节点,因为在链表中的节点就是没有出局的。删除节点只是指针的调整,非常迅速,但是释放删除的节点占用的空间会比较费时,当输入N很大时会占用大量的时间。所以采用一种链表与数组结合的方式,可以克服两种方式的缺点。
结合的方式就是把链表放在一个数组中!初始时,每个元素的next指针指向数组的下一个元素,最后一个指向第一个(我们需要的是一个循环链表)。这样我们就可以实现在数组中跳跃性的访问而不必关心访问的节点是否是被标记为出局,最后只要一次性释放掉数组所占用的空间就好了,不用管链表节点的释放!

#include "stdafx.h"
#include <iostream>

using namespace std;

struct person
{
    int id;
    person* next;
};

struct person_list
{
    int count;
    person* first;
    person* last;
};

person_list* init(int n)
{
    person* p = new person[n];
    for (int i = 0; i < n - 1; ++i)
    {
        p[i].id = i + 1;
        p[i].next = &p[i+1];
    }
    p[n - 1].id = n;
    p[n - 1].next = &p[0];
    person_list* persons = new person_list;
    persons->count = n;
    persons->first = p;
    persons->last = &p[n - 1];
    return persons;
}

int* solve(int n,int m)
{
    if(n < 1 || m < 0) return NULL;
    person_list* persons = init(n);
    person* first = persons->first;
    person* t = first;
    int count = persons->count;
    int *losers = new int[n];
    int j = 0;
    while(count > 1)
    {
        person* q = NULL;
        for (int i = 0; i < m; ++i)
        {
            q = first;
            first = first->next;
        }
        if(first == persons->first)
        {
            persons->first = first->next;
            persons->last =  persons->first;
        }
        else if(first == persons->last)
        {
            q->next = first->next;
            persons->last = q;
        }
        else
        {
            q->next = first->next;
        }
        --count;
        losers[j++] = first->id;
        first = first->next;
    }
    losers[j] = persons->first->id;
    delete []t;
    delete persons;
    return losers;
}

int _tmain(int argc, _TCHAR* argv[])
{
    int n = 5, m = 1;
    int* losers = solve(n,m);
    for (int i = 0; i < n; ++i)
    {
        cout<<losers[i]<<' ';
    }
    cout<<endl;
    delete[]losers;
    return 0;
}

这里写图片描述
程序中losers数组的最后一个元素保存的是最后胜利的人,之前才是出局人序列。
生活中许多事情也像写程序,哪里不会出点bug呢,但是bug总会被修复的不是吗?

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值