C++基础版 7-28 猴子选大王 (20 point(s))

这篇博客介绍了一种猴子选大王的算法,通过C++编程实现。每轮从1号开始报数,报到3的猴子退出,最终剩下的一只为猴王。程序接收正整数N作为输入,输出猴王的编号。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一群猴子要选新猴王。新猴王的选择方法是:让N只候选猴子围成一圈,从某位置起顺序编号为1~N号。从第1号开始报数,每轮从1报到3,凡报到3的猴子即退出圈子,接着又从紧邻的下一只猴子开始同样的报数。如此不断循环,最后剩下的一只猴子就选为猴王。请问是原来第几号猴子当选猴王?

输入格式:

输入在一行中给一个正整数N(≤1000)。

输出格式:

在一行中输出当选猴王的编号。

输入样例:

11

输出样例:

7
//7-28 猴子选大王
#include <stdio.h>
#include <iostream>
using namespace std;

//创建节点对象,包含next指针,和该节点存储的数据
class Node{
public:
    Node* next;
    int data;
    int index;
};

//创建单循环链表对象,其中头结点和该链表的长度均为私有
class circlelist{
private:
    Node* head;
    int length;
public:
    //链表初始化
    circlelist(){
        head = new Node();
        head->next = head;
        head->data = 0;
        length = 0;
    }
    //析构函数
    ~circlelist(){
        delete (head);
    }
    void createCircleList(int n);//创建单向循环链表
    void traverseNode();//遍历链表
    void deleteNode(int n);//删除位置n的节点
    void insertNode(int n, int data);//在位置n上插入int类型的data
    int getLength();//获取链表的长度
    bool isEmpty();//判断链表是否为空
    Node* returnHeadNode();//返回头结点
};

//新建一个长度为n的单循环链表
void circlelist::createCircleList(int n) {
    if (n < 0){
        cout<<"Wrong Length!\n";
    } else{
        //链表的长度设置为n
        length = n;
        //cout<<"Input the data:\n";
        //新建两个节点,其中之一为头结点
        Node *p,*q;
        p = head;
        int i = 1;
        while (n--){
            //从头结点开始,首先新建一个节点
            q = new Node();
            q->data = i;
            //输入该节点存储的数据
            //cin>>q->data;
            //将头结点的next指针置为该新建的节点
            p->next = q;
            //该节点的next指针置为头结点
            q->next = head;
            //将新建的节点作为下一次连接的前驱节点
            p = q;
            //该节点对应的index即为i
            p->index = i;
            i++;
        }
    }
}

//遍历该单循环链表
void circlelist::traverseNode() {
    Node *p;
    p = head->next;
    while (p!=head){
        //测试输出
        cout<<"Index "<<p->index<<":"<<p->data<<"\n";
//        cout<<p->data<<" ";
        p = p->next;
    }
//    cout<<"\n";
}

//删除位置n上的节点
void circlelist::deleteNode(int n) {
    if (n < 0 || n > length){
        cout<<"Wrong Position!\n";
        return;;
    } else{
        Node *p,*q;
        p = head;
        for (int i = 1; i < n; ++i) {
            p = p->next;
        }
        //找到位置n的节点,赋值于q
        q = p->next;
        //重点是要处理前后的链接关系
        p->next = q->next;
        //删除位置n节点之后,后面所有节点的index全部都要减去1
        Node *temp;
        temp = p->next;
        while (temp != head){
            temp->index--;
            temp = temp->next;
        }
        //删除该节点
        delete q;
        q = NULL;
    }
}

//在位置n上插入数据data
void circlelist::insertNode(int n, int data) {
    Node *p,*q;
    p->data = data;
    q = head;
    for (int i = 1; i < n; ++i) {
        q = q->next;
    }
    p->next = q->next;
    q->next = p;
}

//我知道哪里出问题了,是因为getlength的时候返回的是设定的length
//而且评判的时候判断的标准也是用的getlength返回的值
//但是删除操作之后,整个链表的长度是会发生改变的,所以这里是错的。
//获取该单循环链表的长度
int circlelist::getLength() {
    Node *p;
    int length = 0;
    p = head;
    do{
        p = p->next;
        length++;
    }while (p->next != head);
    return length;
}

//判断该单循环链表是否为空
bool circlelist::isEmpty() {
    return head==head->next;
}

//返回头结点
Node* circlelist::returnHeadNode() {
    return head;
}


int main(){
    int n = 0;
    cin>>n;
    if (n > 1000 || n < 0){
        return 0;
    }
    circlelist clist;
    clist.createCircleList(n);
    //现在创建了一个单链表,且单链表中
//    clist.traverseNode();
    /*int length = clist.getLength();
    cout<<"Length of Cyclelist is:"<<length<<"\n";*/
//    clist.deleteNode(3);
//    cout<<"----------\n";
//    clist.traverseNode();

    //测试返回单循环链表的头结点
    Node *head = clist.returnHeadNode();
//    cout<<head->next->index;
    //从头结点的下一个节点开始计算
    Node *p = head->next;
/*    //打印所有节点对应index及其data
    for (int i = 1; i <= n ; ++i) {
        cout<<"Index "<<p->index<<":"<<p->data<<"\n";
        p = p->next;
    }*/
    //此时执行完之后p为空节点,p->next->index = 1
    //cout<<p->next->index<<"\n";
//    cout<<p->index<<"\n";
//    cout<<p->next->index<<"\n";
//    p = p->next->next;
    int A[n];
    int  i = 0,tmp = 0;
    //找到其中要被删掉的节点的index,并存储在数组A中
//    cout<<clist.getLength()<<"\n";
    int count = 0;
    int round = 0;
    cout<<"Original Clist:\n";
    clist.traverseNode();
    cout<<"\n";
    do{
        tmp = i;
        round ++;
        for (int k = 1; k <= clist.getLength() ; ++k) {
            if ((p->index + count)%3==0){
                A[i] = p->index;
                i++;
            }
            p = p->next;
        }

        //如果在这里设置p=p->next,将会出错
        //因为加入删掉最后一个节点,则就会使得p=p->next->next,就是越过第一个节点开始往后计算
        //从而出现错误,这里卡了好久。
        //所以应该是所有要删除的节点都已经删掉之后
        //再把p设置为p->next,此时才指向第一个节点

        //此时p指向第一个节点
        cout<<"需要删除的索引位置:\n";
        for (int j = 0; j < i; ++j) {
            cout<<A[j]<<" ";
        }

        int length = clist.getLength();
        cout<<"\n----After round"<<round<<" delete----\n";
        //这里倒序删除,正向删除会因为前面先删除之后index也更新,删除的就是当删除的后面的值

        for (int j = i - 1; j >= tmp; --j) {
            clist.deleteNode(A[j]);
        }

        //此时p为头结点,p->index = 0
        //所以才会把0写进A中
        p = p->next;

        clist.traverseNode();
        cout<<"The length of Clist is:"<<clist.getLength()<<"\n";
//        count = clist.getLength() % 3;
//        cout<<p->data<<"\n";
        count = (count + length) % 3;
        cout<<"count:"<<count<<"\n\n";
    }while (clist.getLength()!=1);

    return 0;

}

诸以记之,与君共勉~

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值