【问题描述】
n 个人(编号从1~n)围成一圈,从第 k 个人开始数数,数到 m 的人出圈,然后继续从未出列的下一个人开始数数,数到 m 的人出圈,重复上述过程,直到圈中仅剩下一人。
【输入形式】
输入为一行三个正整数,n、k、m。
【输出形式】
输出为一个正整数,表示最后剩下的人的编号。
【样例输入】
100 1 5
【样例输出】
47
【答题提醒】本题为程序片段题,你需要将程序补充完整。题目为类与对象的应用,构造一个循环链表,你需要完全理解本程序的设计思想。
实现思路和注释仅供自己理解,不一定正确
#include <iostream>
using namespace std;
class person//看做person节点
{
private:
int no; //人的编号
person *next; //指向相邻的下一个人
public:
person(int num)
{
no=num;
next=NULL;//初始化next指针为空指针
}
void setNext(person *p)//方便next指针存放person类指针
{
next=p;
}
int getNo()
{
return no;
}
person *getNext()
{
return next;
}
};
class cycle
{
private:
person *start; //开始数数的位置
int out; //数到几出列
int inQueue; //队伍中现有人数
public:
cycle(int num, int from, int whoOut)//num对应n,from对应k,whoout对应m
{
inQueue=num,out=whoOut;//赋值,把n赋值给inQueue,把m赋值给out
person *prv=NULL,*first=NULL;//指针初始化,都设为空指针,pre是previous,之前的意思,这里指上一个
for(int i=1;i<=num;i++)
{person *p=new person(i);//动态开辟内存
if (i==1)//当i是1时
first=p;//把头节点等价于p
if (i==from)//当i是k时
start=p;//开始数数的节点等价于p
if (i>1)//当i大于1时
prv->setNext(p);//类外调用成员函数,prv指针的next指针等价于p
prv=p;//prv可看作一个移动的大箭头,不断在遍历链表
}
prv->setNext(first);//当完整循环完后,把头指针再存到最后一个prv的next指针,从而使得循环成立,简而言之,链表变成了一个圈
}
int getInQueue()
{
return inQueue;//得到队伍的人数
}
void cnt()//根据题目要求数数,确定出列的人,将该人从圈中剔除
{person *q,*temp;
q=start;//先初始化,由于该函数是起剔除作用,所以一上来就让q等于start
temp=NULL;//初始化为空指针
for(int i=1;i<out;i++){//在到第m人出列之前
temp=q;//储存q的信息
q=q->getNext();//q自身返回next指针,即遍历链表中
}
//遍历到out前那个人之后
if(out==1){//如果第一人就是被淘汰的人
start=q->getNext();//start指针就是第一个人的next指针,就是指向下一个人,方便继续遍历
inQueue--;//少了一个人,所以圈内人数减一
delete q;//这个人被淘汰了,所以释放这个节点的内存,这就解释了为什么释放之前要把这个人的next指针传给start指针
}
else{temp->setNext(q->getNext());//这行代码很关键,out前一个人q里的next指针存在了temp里的next指针,如果没有这个储存,链表会断掉
//原因是线性结构遭到破坏,上一个节点不能找到指向下一个节点的指针,上面out=1的情况,由于是第一个节点都直接被删除,所以不需要保存指向下一个节点的指针
start=q->getNext();//同上
inQueue--;//同上
delete q;//同上
}
}
person *getStart()
{
return start;
}
~cycle()
{
delete start;//析构并释放头节点
}
};
int main()
{ int n,k,m;//n是一开始圈有多少人 k是从第k人开始数数 m是数到第m人出列
cin>>n>>k>>m;
cycle *p=new cycle(n,k,m);
while(p->getInQueue()>1)//当队伍剩余人数仍不为1时,调用cnt函数,剔除无关人员
p->cnt();
person *winer=p->getStart(); //剔除完后,令指针winer得到start指针(都是person类)
cout<<winer->getNo()<<endl;//调用得到编号的成员函数,输出剩下的人的成员编号
delete p;
return 0;
}