Qt C++春晚刘谦魔术约瑟夫环问题的模拟程序

什么是约瑟夫环问题?

约瑟夫问题是个有名的问题:N个人围成一圈,从第一个开始报数,第M个将被杀掉,最后剩下一个,其余人都将被杀掉。例如N=6,M=5,被杀掉的顺序是:5,4,6,2,3。
分析:
(1)由于对于每个人只有死和活两种状态,因此可以用布尔型数组标记每个人的状态,可用true表示死,false表示活。
(2)开始时每个人都是活的,所以数组初值全部赋为false。
(3)模拟杀人过程,直到所有人都被杀死为止。

魔术

1、4张牌对折后撕开,就是8张,叠放在一起就是ABCDABCD。注意,ABCD四个数字是完全等价的。
2、根据名字字数,把顶上的牌放到下面,但怎么放都不会改变循环序列的相对位置。譬如2次,最后变成CDABCDAB;譬如3次,最后换成DABCDABC。但无论怎么操作,第4张和第8张牌都是一样的。
3、把顶上3张插到中间任意位置。这一步非常重要!因为操作完之后必然出现第1张和第8张牌是一样的!以名字两个字为例,可以写成BxxxxxxB(这里的x是其他和B不同的牌)。
4、拿掉顶上的牌放到一边,记为B。剩下的序列是xxxxxxB,一共7张牌。
5、南方人/北方人/不确定,分别拿顶上的1/2/3张牌插到中间,但是不会改变剩下7张牌是xxxxxxB的结果。
6、男生拿掉1张,女生拿掉2张。也就是男生剩下6张,女生剩下5张。分别是xxxxxB和xxxxB。
7、把最顶上的放到最底下,循环7次,男生和女生分别会是xxxxBx和xxBxx。
8、最后执行约瑟夫环过程!操作到最后只剩下1张。当牌数为6时(男生),剩下的就是第5张牌;当牌数为5时(女生),剩下的就是第3张牌。就是第4步拿掉的那张牌!

![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/1157e96989d6436ea8772e76b1130263.png

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
brand.h

#ifndef BRAND_H
#define BRAND_H

#include <QLabel>

class Brand:public QLabel
{
public:
    Brand(QWidget* parent=0);
    void SetStr(QString str);
    QString GetStr();
    QPointF GetPointF(){return QPointF(x(), y());}

    void Move(QPointF startPointF, QPointF endPointF);
    void MoveLeft(int step);
    void MoveRight(int step);
    void MoveTop();
    void MoveBottom();
    void Remove();

private:
    QString m_str;
};

#endif // BRAND_H

brand.cpp

#include "brand.h"
#include <QPropertyAnimation>

Brand::Brand(QWidget* parent): QLabel(parent)
{
    resize(20,40);
    setAttribute(Qt::WA_StyledBackground,true);
    setStyleSheet("border: 1px solid rgb(0,0,0);");
}

void Brand::SetStr(QString str)
{
    m_str = str;
    setText(str);
}

QString Brand::GetStr()
{
    return m_str;
}

void Brand::Move(QPointF startPointF, QPointF endPointF)
{
/**********××××××××××××××× 几何动画 ××××××××××××××************/
    //几何属性动画初始化                              目标          属性
    QPropertyAnimation *propertyAnimation = new QPropertyAnimation(this,"geometry");
    //设置动画起始值 QRect(int left, int top, int width, int height)
    propertyAnimation->setStartValue(QRect(startPointF.x(),startPointF.y(),width(),height()));
    //设置某个时间段值
    propertyAnimation->setEndValue(QRect(endPointF.x(),endPointF.y(),width(),height()));//设置结束值
    propertyAnimation->setDuration(1000);//设置动画时长
    propertyAnimation->setLoopCount(1);//设置动画循环周期
    propertyAnimation->setEasingCurve(QEasingCurve::InOutQuad);//设置动画的缓和曲线(动画曲线)

    propertyAnimation->start();
}

void Brand::MoveLeft(int step)
{
    Move(GetPointF(), GetPointF() - QPointF(step*width(),0));
}

void Brand::MoveRight(int step)
{
    Move(GetPointF(), GetPointF() + QPointF(step*width(),0));
}

void Brand::MoveTop()
{
    Move(GetPointF(), GetPointF() - QPointF(0,height()));
}

void Brand::MoveBottom()
{
    Move(GetPointF(), GetPointF() + QPointF(0,height()));
}

void Brand::Remove()
{
    Move(QPointF(x(), y()), QPoint(0,0));
    hide();
}

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <vector>
#include "brand.h"
#include <QPushButton>
#include <QRadioButton>
#include <QLineEdit>
#include <QLayout>
#include <QStackedWidget>
#include <QSplitter>
#include <QButtonGroup>
class Step: public QWidget
{
public:
    Step(QWidget *parent = 0):QWidget(parent){
        QVBoxLayout* vbox = new QVBoxLayout(this);
        QHBoxLayout* hboxLabel = new QHBoxLayout;
        hboxChoose = new QHBoxLayout;
        QHBoxLayout* hboxBtn = new QHBoxLayout;
        label = new QLabel(this);
        hboxLabel->addStretch();
        hboxLabel->addWidget(label);
        hboxLabel->addStretch();
        hboxBtn->addStretch();
        vbox->addLayout(hboxLabel);
        vbox->addLayout(hboxChoose);
        vbox->addLayout(hboxBtn);
    }
    void SetText(QString text){
        label->setText(text);
    }

    QHBoxLayout* GetChooseLayout(){
        return hboxChoose;
    }
    virtual bool Check() {
        return true;
    }
private:
    QLabel* label;
    QHBoxLayout* hboxChoose;
};

class Start: public Step
{
public:
    Start(QWidget *parent = 0):Step(parent)
    {
        SetText("请输入四个数字、字母或汉字");
        edit = new QLineEdit(this);
        edit->setPlaceholderText("请输入四个数字、字母或汉字");
        GetChooseLayout()->addWidget(edit);
    }
    QString GetStr(){
        return edit->text();
    }
    bool Check() {
        return edit->text().size() == 4;
    }

private:
    QLineEdit* edit;
};

class First: public Step
{
public:
    First(QWidget *parent = 0):Step(parent)
    {
        SetText("4张牌对折后撕开");
    }
};

class Second: public Step
{
public:
    Second(QWidget *parent = 0):Step(parent)
    {
        SetText("根据名字字数,把顶上的牌放到下面");
        edit = new QLineEdit(this);
        edit->setPlaceholderText("请输入您的名字");
        GetChooseLayout()->addWidget(edit);
    }
    int GetNumber(){
        return edit->text().size();
    }
    bool Check() {
        return edit->text().size() > 0;
    }
private:
    QLineEdit* edit;
};


class Third: public Step
{
public:
    Third(QWidget *parent = 0):Step(parent)
    {
        SetText("把顶上3张插到中间任意位置");
        radio = new QRadioButton("放到第一张后面",this);
        radio1 = new QRadioButton("放到第二张后面",this);
        radio2 = new QRadioButton("放到第三张后面",this);
        radio3 = new QRadioButton("放到第四张后面",this);
        GetChooseLayout()->addWidget(radio);
        GetChooseLayout()->addWidget(radio1);
        GetChooseLayout()->addWidget(radio2);
        GetChooseLayout()->addWidget(radio3);
        radio->setChecked(true);
    }
    int GetChoose(){
        if(radio->isChecked())
            return 1;
        if(radio1->isChecked())
            return 2;
        if(radio2->isChecked())
            return 3;
        if(radio3->isChecked())
            return 4;
        return 1;
    }
private:
    QRadioButton* radio;
    QRadioButton* radio1;
    QRadioButton* radio2;
    QRadioButton* radio3;
};

class Four: public Step
{
public:
    Four(QWidget *parent = 0):Step(parent)
    {
        SetText("拿掉顶上的牌放到一边");
    }
};

class Five: public Step
{
    Q_OBJECT
public:
    Five(QWidget *parent = 0):Step(parent)
    {
        SetText("南方人/北方人/不确定,分别拿顶上的1/2/3张牌插到中间");
        QVBoxLayout* vbox = new QVBoxLayout;
        QHBoxLayout* hbox = new QHBoxLayout;
        QHBoxLayout* hbox1 = new QHBoxLayout;
        QButtonGroup* group = new QButtonGroup(this);
        QButtonGroup* group1 = new QButtonGroup(this);
        radio = new QRadioButton("南方人(顶上1张)",this);
        radio1 = new QRadioButton("北方人(顶上2张)",this);
        radio2 = new QRadioButton("不确定(顶上3张)",this);
        radio3 = new QRadioButton("放到第一张后面",this);
        radio4 = new QRadioButton("放到第二张后面",this);
        radio5 = new QRadioButton("放到第三张后面",this);
        radio6 = new QRadioButton("放到第四张后面",this);
        radio7 = new QRadioButton("放到第五张后面",this);
        hbox->addWidget(radio);
        hbox->addWidget(radio1);
        hbox->addWidget(radio2);
        hbox1->addWidget(radio3);
        hbox1->addWidget(radio4);
        hbox1->addWidget(radio5);
        hbox1->addWidget(radio6);
        hbox1->addWidget(radio7);
        group->addButton(radio);
        group->addButton(radio1);
        group->addButton(radio2);
        group1->addButton(radio3);
        group1->addButton(radio4);
        group1->addButton(radio5);
        group1->addButton(radio6);
        group1->addButton(radio7);
        vbox->addLayout(hbox);
        vbox->addLayout(hbox1);
        GetChooseLayout()->addLayout(vbox);
        radio->setChecked(true);
        radio3->setChecked(true);
        connect(radio, SIGNAL(pressed()), this, SLOT(OnClicked()));
        connect(radio1, SIGNAL(pressed()), this, SLOT(OnClicked1()));
        connect(radio2, SIGNAL(pressed()), this, SLOT(OnClicked2()));
        connect(radio3, SIGNAL(pressed()), this, SLOT(OnClicked3()));
        connect(radio4, SIGNAL(pressed()), this, SLOT(OnClicked4()));
        connect(radio5, SIGNAL(pressed()), this, SLOT(OnClicked5()));
        connect(radio6, SIGNAL(pressed()), this, SLOT(OnClicked6()));
        connect(radio7, SIGNAL(pressed()), this, SLOT(OnClicked7()));
    }
    int GetChoose(){
        if(radio->isChecked())
            return 1;
        else if(radio1->isChecked())
            return 2;
        else if(radio2->isChecked())
            return 3;
        return 1;
    }
    int GetChoose1(){
        if(radio3->isChecked())
            return 1;
        else if(radio4->isChecked())
            return 2;
        else if(radio5->isChecked())
            return 3;
        else if(radio6->isChecked())
            return 4;
        else if(radio7->isChecked())
            return 5;
        return 1;
    }
protected slots:
    void OnClicked(){
        radio6->setEnabled(true);
        radio7->setEnabled(true);
    }
    void OnClicked1(){
        radio6->setEnabled(true);
        radio7->setEnabled(false);
    }
    void OnClicked2(){
        radio6->setEnabled(false);
        radio7->setEnabled(false);
    }
    void OnClicked3(){
        radio1->setEnabled(true);
        radio2->setEnabled(true);
    }
    void OnClicked4(){
        radio1->setEnabled(true);
        radio2->setEnabled(true);
    }
    void OnClicked5(){
        radio1->setEnabled(true);
        radio2->setEnabled(true);
    }
    void OnClicked6(){
        radio1->setEnabled(true);
        radio2->setEnabled(false);
    }
    void OnClicked7(){
        radio1->setEnabled(false);
        radio2->setEnabled(false);
    }

private:
    QRadioButton* radio;
    QRadioButton* radio1;
    QRadioButton* radio2;
    QRadioButton* radio3;
    QRadioButton* radio4;
    QRadioButton* radio5;
    QRadioButton* radio6;
    QRadioButton* radio7;
};

class Six: public Step
{
public:
    Six(QWidget *parent = 0):Step(parent)
    {
        SetText("男生拿掉1张,女生拿掉2张");
        radio = new QRadioButton("男生",this);
        radio1 = new QRadioButton("女生",this);
        GetChooseLayout()->addWidget(radio);
        GetChooseLayout()->addWidget(radio1);
        radio->setChecked(true);
    }
    int GetChoose(){
        if(radio->isChecked())
            return 1;
        if(radio1->isChecked())
            return 2;
        return 1;
    }
private:
    QRadioButton* radio;
    QRadioButton* radio1;
};

class Seven: public Step
{
public:
    Seven(QWidget *parent = 0):Step(parent)
    {
        Init();
    }
    void Init(){SetText("把最顶上的放到最底下,循环7次");}
};

class Last: public Step
{
public:
    Last(QWidget *parent = 0):Step(parent){
        SetText("好运留下来");
        flag = 1;
    }
    void Init(){
        SetText("好运留下来");
        flag = 1;
    }

    void ChangeText(){
        switch(flag){
            case 0:
                flag = 1;
                SetText("好运留下来");
                break;
            case 1:
                flag = 0;
                SetText("烦恼都丢掉");
                break;
            default:
                break;
        }

    }
    int GetFlag(){
        return flag;
    }

private:
    int flag;
};

class Widget : public QSplitter
{
    Q_OBJECT

public:
    Widget(QWidget *parent = 0);
    ~Widget();
private:
    void StartGetData();
    void FirstStep();
    void SecondStep();
    void ThridStep();
    void FourStep();
    void FiveStep();
    void SixStep();
    void SevenStep();
    void LastStep();

    void MoveHeadBrand();
    void Sleep(int msec);

    void Init();
    void UpdateData();
protected slots:
    void OnClicked(bool);
private:
    std::vector<Brand*> m_vecBrand;
    std::vector<Brand*> m_vecBrandAll;
    QString m_firstCard;

    QLabel* label;
    QPushButton* btn;
    QStackedWidget* m_stackedWidget;

    bool bOver;
};

#endif // WIDGET_H


widget.cpp

#pragma execution_character_set("utf-8")
#include "widget.h"
#include <QTime>
#include <QCoreApplication>
#include <QDebug>

Widget::Widget(QWidget *parent)
    : QSplitter(parent)
{
    setOrientation(Qt::Vertical);
    label = new QLabel(this);
    label->setFixedHeight(90);
    QWidget* widget = new QWidget(this);
    m_stackedWidget = new QStackedWidget(this);
    addWidget(label);
    addWidget(widget);
    setStretchFactor(1,2);

    m_stackedWidget->addWidget(new Start);
    m_stackedWidget->addWidget(new First);
    m_stackedWidget->addWidget(new Second);
    m_stackedWidget->addWidget(new Third);
    m_stackedWidget->addWidget(new Four);
    m_stackedWidget->addWidget(new Five);
    m_stackedWidget->addWidget(new Six);
    m_stackedWidget->addWidget(new Seven);
    m_stackedWidget->addWidget(new Last);

    QHBoxLayout* hbox = new QHBoxLayout;
    QVBoxLayout* vbox = new QVBoxLayout;
    btn = new QPushButton("下一步",this);
    hbox->addStretch();
    hbox->addWidget(btn);
    vbox->addWidget(m_stackedWidget);
    vbox->addLayout(hbox);
    widget->setLayout(vbox);
    connect(btn, SIGNAL(clicked(bool)), this, SLOT(OnClicked(bool)));

    bOver = false;

    for(int i=0; i<8; i++){
        Brand* brand = new Brand(label);
        brand->hide();
        m_vecBrandAll.push_back(brand);
    }
    Init();
}

void Widget::Init()
{
    m_vecBrand = m_vecBrandAll;
    for(int i=0; i<m_vecBrand.size(); i++){
        m_vecBrand[i]->hide();
    }
}

Widget::~Widget()
{
}

void Widget::StartGetData()
{
    Start* start = (Start*)m_stackedWidget->widget(0);
    QString str = start->GetStr();
    for(int i=0, j=0; i<m_vecBrand.size(); i++,j++){
        if(i<4)
            m_vecBrand[i]->show();
        if(j == 4)
            j =0;
        m_vecBrand[i]->SetStr(QString(str[j]));
        m_vecBrand[i]->Move(QPointF(0,0), QPointF(100 + 20*i,10));
    }
}

void Widget::FirstStep()
{
    for(int i=0; i<m_vecBrand.size(); i++){
        m_vecBrand[i]->show();
    }
}

void Widget::SecondStep()
{
    Second* second = (Second*)m_stackedWidget->widget(2);
    int number = second->GetNumber();
    for(int i=0; i<number; i++){
        MoveHeadBrand();
        Brand* brand = m_vecBrand[0];
        m_vecBrand.erase(m_vecBrand.begin());
        m_vecBrand.push_back(brand);
        Sleep(1000);
    }
}

void Widget::ThridStep()
{
    Third* third = (Third*)m_stackedWidget->widget(3);
    int number = third->GetChoose();

    //move
    m_vecBrand[0]->MoveRight(number);
    m_vecBrand[1]->MoveRight(number);
    m_vecBrand[2]->MoveRight(number);
    for(int i=3;i<m_vecBrand.size();i++){
        if(i - 3 < number)
            m_vecBrand[i]->MoveLeft(3);
    }

    Brand* brand = m_vecBrand[0];
    Brand* brand1 = m_vecBrand[1];
    Brand* brand2 = m_vecBrand[2];

    m_vecBrand.erase(m_vecBrand.begin());
    m_vecBrand.erase(m_vecBrand.begin());
    m_vecBrand.erase(m_vecBrand.begin());

    std::vector<Brand*> vecBrand;
    for(int i=0; i<m_vecBrand.size(); i++){
        vecBrand.push_back(m_vecBrand[i]);
        if(number == i + 1){
            vecBrand.push_back(brand);
            vecBrand.push_back(brand1);
            vecBrand.push_back(brand2);
        }
    }
    m_vecBrand = vecBrand;
}

void Widget::FourStep()
{
    //move
    m_vecBrand[0]->Move(m_vecBrand[0]->GetPointF(), QPointF(width() - m_vecBrand[0]->width(),10));
    for(int i=1; i< m_vecBrand.size();i++){
        m_vecBrand[i]->MoveLeft(1);
    }
    m_firstCard = m_vecBrand[0]->GetStr();
    setWindowTitle("当前选择牌为:"+ m_firstCard);
    m_vecBrand.erase(m_vecBrand.begin());
}

void Widget::FiveStep()
{
    Five* five = (Five*)m_stackedWidget->widget(5);
    int number = five->GetChoose();
    int number1 = five->GetChoose1();
qDebug()<<"number:"<<number;
qDebug()<<"number1:"<<number1;
    //move
    for(int i=0;i<number;i++){
        m_vecBrand[i]->MoveRight(number1);
    }
    for(int i=number;i<number + number1;i++){
        m_vecBrand[i]->MoveLeft(number);
    }


    std::vector<Brand*> vecBrand;
    for(int i=0; i<number;i++){
        vecBrand.push_back(m_vecBrand[0]);
        m_vecBrand.erase(m_vecBrand.begin());
    }

    std::vector<Brand*> vecBrand1;
    for(int i=0; i<m_vecBrand.size(); i++){
        vecBrand1.push_back(m_vecBrand[i]);
        if(number1 == i + 1){
            vecBrand1.insert(vecBrand1.end(), vecBrand.begin(), vecBrand.end());
        }
    }
    m_vecBrand = vecBrand1;
}

void Widget::SixStep()
{
    Six* six = (Six*)m_stackedWidget->widget(6);
    int number = six->GetChoose();
    switch (number) {
    case 1:
        m_vecBrand[0]->Remove();
        for(int i=1;i<m_vecBrand.size();i++)
            m_vecBrand[i]->MoveLeft(1);
        m_vecBrand.erase(m_vecBrand.begin());
        break;
    case 2:
        m_vecBrand[0]->Remove();
        m_vecBrand[1]->Remove();
        for(int i=2;i<m_vecBrand.size();i++)
            m_vecBrand[i]->MoveLeft(1);
        m_vecBrand.erase(m_vecBrand.begin());
        m_vecBrand.erase(m_vecBrand.begin());
        break;
    default:
        break;
    }
}

void Widget::SevenStep()
{
    Seven* seven = (Seven*)m_stackedWidget->widget(7);
    for(int i=0; i<7; i++){
        seven->SetText(QString("循环第%1次").arg(i+1));
        m_vecBrand[0]->MoveRight(m_vecBrand.size()-1);
        for(int j=1;j<m_vecBrand.size();j++)
            m_vecBrand[j]->MoveLeft(1);
        Sleep(1000);

        Brand* brand = m_vecBrand[0];
        m_vecBrand.erase(m_vecBrand.begin());
        m_vecBrand.push_back(brand);
    }
    seven->Init();
}

void Widget::LastStep()
{
    Last* last = (Last*)m_stackedWidget->widget(8);
    int flag = last->GetFlag();
    switch (flag) {
    case 0:
        m_vecBrand[0]->hide();
        m_vecBrand.erase(m_vecBrand.begin());
        break;
    case 1:
        m_vecBrand[0]->MoveRight(m_vecBrand.size()-1);
        for(int j=1;j<m_vecBrand.size();j++)
            m_vecBrand[j]->MoveLeft(1);
        Brand* brand = m_vecBrand[0];
        m_vecBrand.erase(m_vecBrand.begin());
        m_vecBrand.push_back(brand);
        break;
    }

    last->ChangeText();
}

void Widget::MoveHeadBrand()
{
    for(int i=1; i<m_vecBrand.size();i++){
        m_vecBrand[i]->MoveLeft(1);
    }
    m_vecBrand[0]->MoveRight(7);
}

void Widget::Sleep(int msec)
{
    QTime dieTime = QTime::currentTime().addMSecs(msec);
    while( QTime::currentTime() < dieTime )
        QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
}


void Widget::UpdateData()
{
    QString str;
    for(int i=0; i<m_vecBrand.size(); i++){
        str+= m_vecBrand[i]->GetStr();
    }
    label->setText(str);
}

void Widget::OnClicked(bool)
{
    if(bOver){
        Init();
        setWindowTitle("magic");
        Last* last = (Last*)m_stackedWidget->widget(8);
        last->Init();
        bOver = false;
        btn->setText("下一步");
        m_stackedWidget->setCurrentIndex(0);
        return;
    }

    Step* step = (Step*)m_stackedWidget->currentWidget();
    if(!step->Check())
        return;

    if(m_vecBrand.size() == 1){
        m_vecBrand.clear();
        Last* last = (Last*)m_stackedWidget->widget(8);
        last->SetText("之前的牌为:"+ m_firstCard+ " 对上否?");
        bOver = true;
        btn->setText("重新开始");
        return;
    }

    switch (m_stackedWidget->currentIndex()) {
    case 0://4张牌
        StartGetData();
        break;
    case 1://对折撕开
        FirstStep();
        break;
    case 2://根据名字字数,把顶上的牌放到下面
        SecondStep();
        break;
    case 3://把顶上3张插到中间任意位置
        ThridStep();
        break;
    case 4://拿掉顶上的牌放到一边
        FourStep();
        break;
    case 5://南方人/北方人/不确定,分别拿顶上的1/2/3张牌插到中间
        FiveStep();
        break;
    case 6://男生拿掉1张,女生拿掉2张
        SixStep();
        break;
    case 7://把最顶上的放到最底下,循环7次
        SevenStep();
        break;
    case 8://好运留下来 烦恼都丢掉
        LastStep();
        break;
    default:
        break;
    }
    UpdateData();

    if(m_stackedWidget->currentIndex() + 1 < m_stackedWidget->count())
        m_stackedWidget->setCurrentIndex(m_stackedWidget->currentIndex() + 1);
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值