1. 程式人生 > >騰訊面試題——螞蟻爬行(C++版)

騰訊面試題——螞蟻爬行(C++版)

#include <iostream>
#include <limits>

#include "ctime"
using namespace std;

const double DBL_MAX = numeric_limits<double>::max();

class Ant {

	/**
	 * 螞蟻爬行方向列舉值
	 */
private:
    const double LEFT = -1;
    const double RIGHT = 1;

	/**
	 * 螞蟻所在位置,取值範圍:[0,1]
	 */
	 double position;

	/**
	 * 螞蟻當前爬行的方向
	 */
	 double direction;

	/**
	 * 螞蟻爬行速度
	 */
	 double speed = 1;

	/**
	 * 螞蟻已爬行的時長
	 */
	 double crawlingTime = 0;

	/**
	 * 螞蟻距離下一次碰到其他螞蟻的時間
	 */
 	 double nextMeetingTime = DBL_MAX;

	/**
	 * 螞蟻是否已離開木杆
	 */
	 bool left = false;


    public:

    	/**
	 * 控制螞蟻調頭
	 */
	void turnRound() {
		direction *= -1;
	}

	/**
	 * 當螞蟻不再會跟任何螞蟻相遇時,控制螞蟻直接離開木杆
	 */
	 void leave() {
		if (direction == LEFT) {
			crawlingTime += position / speed;
		} else {
			crawlingTime += (1 - position) / speed;
		}
		nextMeetingTime = DBL_MAX;
		left = true;
	}

	/**
	 * 控制螞蟻爬行一段時間(前提在此段時間內不會和任何螞蟻相遇)
	 *
	 * @param time
	 *            控制螞蟻爬行的時間
	 */
	void crawling(double time) {
		double lastPosition = position;
		position += time * speed * direction;

		// 若爬行結束時螞蟻已離開木杆,則將其離開狀態重新整理為true
		if (position < 0 || position > 1) {
			left = true;
			crawlingTime += (position < 0 ? lastPosition / speed : (lastPosition - 1) / speed);
		}
		crawlingTime += time;
		nextMeetingTime = DBL_MAX;
	}

	/**
	 * 計算和另一隻螞蟻相遇的時間
	 *
	 * @param ant
	 *            另一隻螞蟻
	 * @return 和另一隻螞蟻相遇的時間
	 */
	 double timeToMeet(Ant ant) {
		if (direction * ant.getDirection() > 0) {
			return DBL_MAX;
		}

		if ((direction == LEFT && getPosition() <= ant.getPosition())
				|| (direction == RIGHT && getPosition() >= ant.getPosition()) ){
			return DBL_MAX;
		}

		return (getPosition() + ant.getPosition() ) * 0.5;
	}

	 double getCrawlingTime() {
		return this->crawlingTime;
	}

	 void setCrawlingTime(double crawlingTime) {
		this->crawlingTime = crawlingTime;
	}

	 bool isLeft() {
		return this->left;
	}

	 void setLeft(bool left) {
		this->left = left;
	}

	 double getPosition() {
		return this->position;
	}

	 void setPosition(double position) {
		this->position = position;
	}

	 double getDirection() {
		return this->direction;
	}

	 void setDirection(double direction) {
		this->direction = direction;
	}

	 double getSpeed() {
		return this->speed;
	}

	 void setSpeed(double speed) {
		this->speed = speed;
	}

	 double getNextMeetingTime() {
		return this->nextMeetingTime;
	}

	 void setNextMeetingTime(double nextMeetingTime) {
		this->nextMeetingTime = nextMeetingTime;
	}
};

double allAntsLeftTime(Ant *ants[]);
void crawling(Ant *ants[], double time);
double nextMeeting(Ant *ants[]);
const int ANT_SIZE = 20;

	/**
	 * 計算所有螞蟻離開木杆的耗時
	 *
	 * @param ants 所有螞蟻
	 * @return 所有螞蟻離開木杆的耗時
	 */
	double allAntsLeftTime(Ant *ants[])
	{
		double nextMeetingTime;
		// 若木杆上的螞蟻可能相遇,則控制螞蟻持續爬行,直至不會再出現螞蟻相遇
		while((nextMeetingTime =  nextMeeting(ants)) < DBL_MAX)
		{
            crawling(ants, nextMeetingTime);
		}
		double maxCrawlingTime = 0;

		// 遍歷螞蟻在木杆上爬行的時間,獲取最大值,即為所有螞蟻離開木杆的時間
		for(int i = 0; i < ANT_SIZE; i++)
		{
			// 若螞蟻還未離開木杆,控制其離開
			if(!ants[i]->isLeft())
			{
				ants[i]->leave();
			}
			if( ants[i]->getCrawlingTime() > maxCrawlingTime)
			{
				maxCrawlingTime = ants[i]->getCrawlingTime();
			}
		}
		return maxCrawlingTime;
	}

	/**
	 * 控制所有螞蟻爬行一段時間(前提:在這個時間段內,所有螞蟻都不會相遇)
	 *
	 * @param ants 所有螞蟻
	 * @param time 爬行時間
	 */
    void crawling(Ant *ants[], double time)
	{
		for(int i = 0; i < ANT_SIZE; i++)
		{
			if(ants[i]->isLeft())
			{
				continue;
			}

			// 若當前螞蟻不會再和任何螞蟻相遇,控制其離開,計算爬行時間
			if(ants[i]->getNextMeetingTime() == DBL_MAX)
			{
				ants[i]->leave();
				continue;
			}

			ants[i]->crawling(time);
			if(ants[i]->getNextMeetingTime() == time)
			{
				ants[i]->turnRound();
			}
		}
	}

	/**
	 * 計算下一次出現螞蟻相遇事件的時間
	 *
	 * @param ants 所有螞蟻
	 * @return 下一次出現螞蟻相遇事件的時間
	 */
    double nextMeeting(Ant *ants[]) {
		Ant *ant1, *ant2;
		double timeToMeet;
		// 計算每隻螞蟻與其他螞蟻相遇的最短時間
		// 已離開木杆的螞蟻不會再和任何螞蟻相遇
		for (int i = 0; i < ANT_SIZE; i++) {
			ant1 = ants[i];

			// 若螞蟻1已離開木杆,則無需計算
			if(ant1->isLeft())
			{
				continue;
			}
			// 計算螞蟻1與其他螞蟻相遇的最短時間
			for (int j = i + 1; j < ANT_SIZE; j++) {
				ant2 = ants[j];

				// 若螞蟻2已離開木杆,則無需計算
				if(ant2->isLeft())
				{
					continue;
				}
				timeToMeet = ant1->timeToMeet(*ant2);
				if (timeToMeet == DBL_MAX) {
					continue;
				}

				// 若兩隻螞蟻可以相遇,且相遇時間短於當前最小時間,則重新整理起下次相遇時間
				if (ant1->getNextMeetingTime() > timeToMeet) {
					ant1->setNextMeetingTime(timeToMeet);
				}
				if (ant2->getNextMeetingTime() > timeToMeet) {
					ant2->setNextMeetingTime(timeToMeet);
				}
			}
		}

		// 獲取下一次出現螞蟻相遇的時間點(發生在多久以後)
		double nextMeetTime = DBL_MAX;
		for(int i = 0; i < ANT_SIZE; i++)
		{
			if(ants[i]->getNextMeetingTime() < nextMeetTime)
			{
				nextMeetTime = ants[i]->getNextMeetingTime();
			}
		}
		return nextMeetTime;
	}

int main()
{
    cout << "Hello world!" << endl;

    Ant *ants[ANT_SIZE];

    double leftTime;
    double maxLeftTime = 0;

    srand(time(NULL));
    for(int t = 0; t < 100; t++)
    {
        for(int i = 0; i < ANT_SIZE; i++)
        {
            ants[i] = new Ant();
            ants[i]->setPosition(((double)rand()/RAND_MAX));
            ants[i]->setDirection(((double)rand()/RAND_MAX) > 0.5 ? 1 : -1);
        }
        leftTime = allAntsLeftTime(ants) * 2; //一隻螞蟻爬完木杆耗時2分鐘
        printf("All Ants Left Time: %f\r\n", leftTime);

        if(maxLeftTime < leftTime)
        {
            maxLeftTime = leftTime;
        }
    }
    printf("Max Left Time: %f\r\n", maxLeftTime);

    return 0;
}