[College] 《C++程序设计-实践教程》约瑟夫问题

约瑟夫问题

题目描述

n个人围成一圈,从编号为1的开始从1~m报数,报到m的人离开,接着再从下一个人重新报数。这样反反复复,直到只剩下一个人,求编号为多少的人留下?

输入格式

两个整数n、m。n表示总人数,m表示报数的截止上限。

输出格式

一个整数,表示剩下的人的编号。

AC代码

链表版

#include<iostream>
#include<cstdio>
#include<cstdlib>

using namespace std;

struct  node
{
    int next;//记录当前参与者的后一位的位置
    int post;//记录当前参与者的前一位的位置
};
node circle[1000];

int main()
{
    int num,exit_num,present=1;//定义:剩余人数num,报数上限exit_num,当前位置present
    cout<<"Please input the number of people: "<<endl;
    cin>>num;
    cout<<"Please input the exit number: "<<endl;
    cin>>exit_num;

    //初始化链表为一个圈
    for(int i=1;i<=num;i++)
    {
        circle[i].next=i+1;
        circle[i].post=i-1;
    }
    circle[num].next=1;//最后一位的下一个为第一位
    circle[1].post=num;//第一位的上一位为最后一位

    while(num>1)
    {
        for(int i=1;i<exit_num;i++)//模拟报数
            present=circle[present].next;
        circle[circle[present].post].next=circle[present].next;//对于退出者进行删除操作:上一位的下一位为当前的下一位;下一位的上一位为当前的上一位
        circle[circle[present].next].post=circle[present].post;
        present=circle[present].next;//从当前的下一位再一次开始报数
        num--;//更新剩余人数
    }
    cout<<present<<endl;
    system("pause");
    return 0;
}

采用链表的优势就是:可以非常出色地维护一个环形的结构,并且避免了处理跳过不参与报数的位置,而且在效率上——由于直接跳过了退出的位置——相较于一般的数组更为优秀~ 

不过这个是下学期才学的知识......

数组版

#include<iostream>
#include<cstdio>
#include<cstdlib>

using namespace std;

bool circle[1000];

int main()
{
    int num,exit_num,present=1,cnt;//定义num为初始参与人数,exit_num为报数的上限,present为当前位置,cnt为剩余人数
    cout<<"Please input the number of participants: "<<endl;
    cin>>num;
    cout<<"Please input the exit number"<<endl;
    cin>>exit_num;

    cnt=num;//初始化cnt为总人数
    while(cnt>1)
    {
        for(int i=1;i<=exit_num;i++)//模拟报数
        {
            if(circle[present]==true)//若当前位置的参与者已经退出,则不计入报数,还原i值
                i--;
            else if(i==exit_num)//若当前参与者未退出,且报数已经达到上限,则令其退出
                circle[present]=true;
            present=(present==num)?(1):(present+1);//更新当前位置为下一位
        }
        cnt--;//更新剩余人数
    }
    for(int i=1;i<=num;i++)//遍历整个数组,寻找剩下的唯一参与者
        if(circle[i]==false)
            cout<<i<<endl;
    system("pause");
    return 0;
}

数组版的代码要相对复杂一点,原因在于我们不能对数组结构中的元素进行“删除”操作,这使得我们在遍历时(也就是模拟报数过程时)要考虑已经不参与报数的位置,在更新当前位置present时也要注意模拟环状的结构。另外,由于我们无法通过present的值直接确定答案,我们在最后需要单独从1~num遍历一次数组,找到尚未被标记的位置并输出。

猜你喜欢

转载自www.cnblogs.com/SinGuLaRiTy2001/p/11734342.html
今日推荐