问题描述
n 个人(编号从1~n)围成一圈,从第 k 个人开始数数,数到 m 的人出圈,然后继续从未出列的下一个人开始数数,数到 m 的人出圈,重复上述过程,直到圈中仅剩下一人。
【输入形式】
输入为一行三个正整数,n、k、m。
【输出形式】
输出为一个正整数,表示最后剩下的人的编号。
【样例输入】
100 1 5
【样例输出】
47
【答题提醒】本题为程序片段题,你需要将程序补充完整。题目为类与对象的应用,构造一个循环链表,你需要完全理解本程序的设计思想。
#include <iostream>
using namespace std;
class person
{
private:
int no; /* 人的编号 */
person *next; /* 指向相邻的下一个人 */
public:
person(int num)
{
no=num;
next=NULL;
}
void setNext(person *p)
{
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)
{
inQueue=num; out=whoOut;
person *prv=NULL,//指向前一个人
*first=NULL;//每次循环始终指向链表第一个节点
for(int i=1; i<=num; i++)
{
person *p=new person(i);//分配堆内存,调用构造带参数的构造函数,并初始化
if (i==1)
first=p;//first指针指向第一个人
if (i==from)
start=p;//start指针指向开始的人
if (i>1)
prv->setNext(p);//1式
prv=p;//2式
//1、2两式是把链表的一个一个节点连接起来:
//先指向p的prv在下一个循环中把p的next指针指向现在的p‘
}
prv->setNext(first);//最后一个人指向最初的人,成环了
}
int getInQueue()
{
return inQueue;
}
void cnt() /* 根据题目要求数数,确定出列的人,将该人从圈中剔除 */
{
person *f=start;
//移走人的时候需要两个节点同时往后找,前一个为prv,后一个为f
//移走人的时候把prv的next指向f的next就行了
while(f->getNext()!=start)//这一步是在找“开始人”的前一个人
f=f->getNext();
person *prv=f;
f=start;
for(int i=1; i<out; i++)
{
//开始找被踢掉的小孩的前一个人了
prv=f;
f=f->getNext();
}
inQueue--;//人数减1
prv->setNext(f->getNext());//踢他
start=f->getNext();
delete f;//好习惯
}
person *getStart()
{
return start;
}
~cycle()//好习惯
{
delete start;//好习惯
}
};
int main()
{
int n,k, m ; /* n 圈内人数 k 开始数数 m 可数出列 */
cin>>n>>k>>m;
cycle *p=new cycle(n,k,m);
while(p->getInQueue()>1)
p->cnt();
person *winer=p->getStart();
cout<<winer->getNo()<<endl;
delete p;
return 0;
}