生成n位全部二进制数,数组形式:蚂蚁爬杆问题

OOAD第一次项目,以OOAD思想实现蚂蚁爬杆问题解法

先重述一下蚂蚁爬杆问题:

有一根300 厘米的细木杆,在第30 厘米、80 厘米、110 厘米、160 厘米、250厘米这五个位置上各有一只蚂蚁。木杆很细,不能同时通过两只蚂蚁。

开始时,蚂蚁的头朝左还是朝右是任意的,它们只会朝前走或调头,但不会后退。 当任意两只蚂蚁碰头时,两只蚂蚁会同时调头朝相反方向走。假设蚂蚁们每秒钟可以走5 厘米的距离。

注:不允许穿越对方身体继续直行 请编写一个程序,计算各种可能情形下所有蚂蚁都离开木杆的最小时间和最大时间。

在编写过程中设置了一个GameRoom类用于模拟运行全部蚂蚁的爬行情况,其中需要一个函数来生成所有可能的方向组合。

我在写几个类的头文件最开始定义了一个游戏数据结构体,用于存放每一种方向组合的具体蚂蚁初试方向与游戏的结束时间:

struct GameData
{
    bool antDirection[DefaultAnt.antcnt];
    int gameTime;
};

同时在蚂蚁类中以bool值定义了蚂蚁行进的方向,以右为正:

/*
 The Ant class.
 */
class Ant
{
private:
    int antId;
    double velocity;
    bool direction;     // True stands for right.
    double location;
    bool isAlive;       // True stands for alive.
    
public:
    
};

GameRoom类如下构造:

/*
 The GameRoom class.
 */
class GameRoom
{
private:
    int incTime;
    GameData stGameData[DefaultAnt.GroupCnt];
    
public:
    GameRoom ();
    
    void buildDirections ();
    void playGames ();
    void start ();
    
};

初步思想如下:

将结构体数组中按用于存放方向的数组展开,组合成2^n行,n列的矩阵:

stGameData[0].antDirection[0]

stGameData[0].antDirection[1]stGameData[0].antDirection[2]···stGameData[0].antDirection[n-1]
stGameData[1].antDirection[0]stGameData[1].antDirection[1]stGameData[1].antDirection[2]···stGameData[1].antDirection[n-1]
stGameData[2].antDirection[0]stGameData[2].antDirection[1]stGameData[2].antDirection[2]···stGameData[2].antDirection[n-1]
···············
stGameData[2^n-2].antDirection[0]stGameData[2^n-2].antDirection[1]stGameData[2^n-2].antDirection[2]···stGameData[2^n-2].antDirection[n-1]
stGameData[2^n-1].antDirection[0]

stGameData[2^n-1].antDirection[1]

stGameData[2^n-1].antDirection[2]

···

stGameData[2^n-1] .antDirection[n-1]

 第一列自上而下依次赋值0, 1, 0, 1, 0, 1, ···

第二列自上而下依次赋值0, 0, 1, 1, 0, 0, 1, 1, ···

第三列自上而下依次赋值0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, ···

因而如下构造生产函数:

/*
 Post: Every situation is generalized.
 */
void GameRoom::buildDirections ()
{
    for (int divis = 0; divis < DefaultAnt.antcnt; divis ++)
    {
        int tmpdivi = pow (2, divis);
        for (int i = 0; i < DefaultAnt.GroupCnt; i += 2 * tmpdivi)
        {
            for (int j = i; j < tmpdivi; j ++)
                stGameData[j].antDirection[divis] = true;
            for (int p = i + tmpdivi; p < i + 2 * tmpdivi; p ++)
                stGameData[p].antDirection[divis] = false;
        }
    }
}

第一层for循环用于设置计算n次,第二层for循环用于计算每一个结构题内方向数组应从第几位开始赋值0,最内层的两个for循环用于赋值0和1

算法时间复杂度可能稍高······

最后贴上OOAD思想写的爬杆问题解法:

//
//  Ant.h
//  Ant
//
//

#ifndef Ant_h
#define Ant_h

#include <math.h>

struct DefaultStickData
{
    const double leftEnd = 0;
    const double rightEnd = 300;
};

struct DefaultAntData
{
    const int antcnt = 5;
    const int GroupCnt = 32;
    const double speed = 5;
    const bool direct = true;
    const double loc[5] = {30, 80, 110, 160, 250};
};

const DefaultStickData DefaultStick;
const DefaultAntData DefaultAnt;



struct GameData
{
    bool antDirection[DefaultAnt.antcnt];
    int gameTime;
};


/*
 The Ant class.
 */
class Ant
{
private:
    int antId;
    double velocity;
    bool direction;     // True stands for right.
    double location;
    bool isAlive;       // True stands for alive.
    
public:
    Ant ();
    void setAnt (int antID, double vel, bool dir, double loc);
    
    void changeDirection ();
    void creeping ();
    bool isColllision (bool isCol);
    bool isLive ();
    void changeLive ();
    
    double getLocation ();
    double getVelocity ();
    bool getDirection ();
    
};

/*
 Post: Ant class is initialized.
 */
Ant::Ant ()
{
    
}

void Ant::setAnt (int antID, double vel, bool dir, double loc)
{
    antId = antID;
    velocity = vel;
    direction = dir;
    location = loc;
    isAlive = true;
}

/*
 Post: The ant's direction is changed.
 */
void Ant::changeDirection ()
{
    if (isAlive)
        direction = !direction;
}

/*
 The function keeps the ant creeping by 1 second.
 */
void Ant::creeping ()
{
    if (isAlive)
        if (direction == true)
            location += velocity;
        else
            location -= velocity;
}

/*
 Post: This function returns a bool value on the basis of isCol given by the detectCollision function in CreepingGame.
 */
bool Ant::isColllision (bool isCol)
{
    return isCol;
}

/*
 Post: The status of the ant is retuned.
 */
bool Ant::isLive ()
{
    return isAlive;
}

/*
 Post: The status of the ant is changed.
 */
void Ant::changeLive ()
{ 
    if (isAlive)
        isAlive = !isAlive;
}

/*
 Post: The function prints the ant's location.
 */
double Ant::getLocation ()
{
    return location;
}

/*
 Post: The function prints the ant's velocity.
 */
double Ant::getVelocity ()
{
    return velocity;
}

/*
 Post: The function prints the ant's direction.
 */
bool Ant::getDirection()
{
    return direction;
}


/*
 The Stick class.
 */
class Stick
{
private:
    double leftLocation;
    double rightLocation;
    int livingAnts;
    
public:
    Stick ();
    void setStick (double leftLoc, double rightLoc);
    
    bool isOut (Ant tmpAnt);
    
    void killAnt ();
    int getLivAntCnt ();
    
};

/*
 Post: The stick is initialized, giving the value of leftLocation is smaller than that of rightLocation.
 */
Stick::Stick ()
{
    
}

void Stick::setStick (double leftLoc, double rightLoc)
{
    leftLocation = leftLoc;
    rightLocation = rightLoc;
    livingAnts = DefaultAnt.antcnt;
}

/*
 Post: The function examines whether the given ant is out of the stick, true stands for out.
 */
bool Stick::isOut (Ant tmpAnt)
{
    if (tmpAnt.getLocation () <= leftLocation || tmpAnt.getLocation () >= rightLocation)
        return true;
    return false;
}

/*
 Post: The amount of ants decreases by 1.
 */
void Stick::killAnt ()
{
    livingAnts --;
}

/*
 Post: The amount of living ants is returned.
 */
int Stick::getLivAntCnt ()
{
    return livingAnts;
}


/*
 The CreepingGame class.
 */
class CreepingGame
{
private:
    int gameTime;
    bool isGameOver;       // True stands for not over.
    double incTim;
    Ant livant[DefaultAnt.antcnt];
    Stick curstick;
    
public:
    CreepingGame (int gameTim = 0, bool isGameOve = false, double incT = 1);
    
    void drivingGame ();
    void startGame (GameData gData);
    void detectCollision ();
    bool isAllDead ();
    
    bool getGameStatus ();
    int getGameTime ();
};

/*
 Post: The Game is initialized.
 */
CreepingGame::CreepingGame (int gameTim, bool isGameOve, double incT)
{
    gameTime = gameTim;
    isGameOver = isGameOve;
    incTim = incT;
}

/*
 Post: The game's time is increased by 1 second;
 */
void CreepingGame::drivingGame ()
{
    while (1)
    {
        gameTime += incTim;
        
        detectCollision ();
        
        for (int i = 0; i < DefaultAnt.antcnt; i++)
            if (livant[i].isLive ())
                livant[i].creeping ();
        
        for (int i = 0; i < DefaultAnt.antcnt; i++)
        {
            if (livant[i].isLive ())
                if (curstick.isOut (livant[i]))
                {
                    livant[i].changeLive ();
                    curstick.killAnt ();
                }
        }
        
        if (isAllDead () == true)
            break;
    }
    
    isGameOver = true;
}

/*
 Post: The game is started and the stick and ants are initialized.
 */
void CreepingGame::startGame (GameData gData)
{
    curstick.setStick (DefaultStick.leftEnd, DefaultStick.rightEnd);
    
    for (int i = 0; i < DefaultAnt.antcnt; i ++)
        livant[i].setAnt (i, DefaultAnt.speed, gData.antDirection[i], DefaultAnt.loc[i]);
    
}

/*
 Post: Collision are detected and ants' directions are changed.
 */
void CreepingGame::detectCollision ()
{
    int tmpantid = -1;
    for (int i = 0; i < DefaultAnt.antcnt; i ++)
    {
        tmpantid = -1;
        if (livant[i].isLive ())
        {
            if (livant[i].getDirection () == true)
            {
                for (int j = 0; j < DefaultAnt.antcnt; j ++)
                    if (livant[j].isLive ())
                    {
                        if (tmpantid == -1)
                        {
                            if (livant[j].getLocation () > livant[i].getLocation ())
                                tmpantid = j;
                        }
                        else
                        {
                            if (livant[j].getLocation () > livant[i].getLocation () && livant[j].getLocation () < livant[tmpantid].getLocation ())
                                tmpantid = j;
                        }
                    }
                if (tmpantid != -1)
                    if (abs (livant[i].getLocation () - livant[tmpantid].getLocation ()) <= (livant[i].getVelocity () + livant[tmpantid].getVelocity ()))
                    {
                        livant[i].changeDirection ();
                        livant[tmpantid].changeDirection ();
                    }
            }
            else
            {
                for (int j = 0; j < DefaultAnt.antcnt; j ++)
                    if (livant[j].isLive ())
                    {
                        if (tmpantid == -1)
                        {
                            if (livant[j].getLocation () < livant[i].getLocation ())
                                tmpantid = j;
                        }
                        else
                        {
                            if (livant[j].getLocation () < livant[i].getLocation () && livant[j].getLocation () > livant[tmpantid].getLocation ())
                                tmpantid = j;
                        }
                    }
                if (tmpantid != -1)
                    if (abs (livant[i].getLocation () - livant[tmpantid].getLocation ()) <= (livant[i].getVelocity () + livant[tmpantid].getVelocity ()))
                    {
                        livant[i].changeDirection ();
                        livant[tmpantid].changeDirection ();
                    }
            }
        }
    }
}

/*
 Post: The function judges whether all the ants are dead.
 */
bool CreepingGame::isAllDead ()
{
    if (curstick.getLivAntCnt () <= 0)
        return true;
    return false;
}

/*
 Post: The status of the game is returned.
 */
bool CreepingGame::getGameStatus ()
{
    return isGameOver;
}

/*
 Post: The time of the game is returned.
 */
int CreepingGame::getGameTime ()
{
    return gameTime;
}


/*
 The GameRoom class.
 */
class GameRoom
{
private:
    int incTime;
    GameData stGameData[DefaultAnt.GroupCnt];
    
public:
    GameRoom ();
    
    void buildDirections ();
    void playGames ();
    void start ();
    
};

/*
 Post: The function initializes the class.
 */
GameRoom::GameRoom ()
{
    incTime = 1;
    
    for (int i = 0; i < DefaultAnt.GroupCnt; i ++)
        stGameData[i].gameTime = 0;
}

/*
 Post: Every situation is generalized.
 */
void GameRoom::buildDirections ()
{
    for (int divis = 0; divis < DefaultAnt.antcnt; divis ++)
    {
        int tmpdivi = pow (2, divis);
        for (int i = 0; i < DefaultAnt.GroupCnt; i += 2 * tmpdivi)
        {
            for (int j = i; j < tmpdivi; j ++)
                stGameData[j].antDirection[divis] = true;
            for (int p = i + tmpdivi; p < i + 2 * tmpdivi; p ++)
                stGameData[p].antDirection[divis] = false;
        }
    }
}

/*
 Post: Games are played.
 */
void GameRoom::playGames ()
{
    CreepingGame creep[DefaultAnt.GroupCnt];
    for (int i = 0; i < DefaultAnt.GroupCnt; i ++)
    {
        creep[i].startGame (stGameData[i]);
        creep[i].drivingGame();
        stGameData[i].gameTime = creep[i].getGameTime ();
    }
    
    int maxtime = 0;
    int mintime = stGameData[0].gameTime;
    
    for (int j = 0; j < DefaultAnt.GroupCnt; j ++)
    {
        if (stGameData[j].gameTime > maxtime)
            maxtime = stGameData[j].gameTime;
        if (stGameData[j].gameTime < mintime)
            mintime = stGameData[j].gameTime;
    }
    
    std::cout << "Max Time is " << maxtime << std::endl;
    std::cout << "Min Time is " << mintime << std::endl;
}

/*
 Post: Game starts.
 */
void GameRoom::start ()
{
    std::cout << "Game started." << std::endl;
    buildDirections ();
    playGames ();
}

#endif /* Ant_h */
//
//  main.cpp
//  Ant
//
//

#include <iostream>
#include "Ant.h"

int main() {
    GameRoom room;
    room.start ();
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值