腾讯面试题——蚂蚁爬行(Java版)

本文介绍了一个蚂蚁博弈模拟程序,通过控制蚂蚁在木杆上的爬行、转向和相遇等行为,研究多只蚂蚁在有限空间内的互动规律。程序实现了蚂蚁类,记录蚂蚁的状态并控制其行为,包括爬行方向、速度、位置等属性,以及与其它蚂蚁相遇后的调头行为。主程序通过多次模拟实验,计算所有蚂蚁离开木杆所需的最大时间。
/**
 * 蚂蚁类,用于记录蚂蚁的状态及控制蚂蚁行为
 */
public class Ant {

	/**
	 * 蚂蚁爬行方向枚举值
	 */
	public interface Direction {
		/**
		 * 向左爬行
		 */
		double LEFT = -1;

		/**
		 * 向右爬行
		 */
		double RIGHT = 1;
	}

	/**
	 * 蚂蚁所在位置,取值范围:[0,1]
	 */
	private double position;

	/**
	 * 蚂蚁当前爬行的方向
	 */
	private double direction;

	/**
	 * 蚂蚁爬行速度
	 */
	private double speed = 1;

	/**
	 * 蚂蚁已爬行的时长
	 */
	private double crawlingTime;

	/**
	 * 蚂蚁距离下一次碰到其他蚂蚁的时间
	 */
	private double nextMeetingTime = Double.MAX_VALUE;

	/**
	 * 蚂蚁是否已离开木杆
	 */
	private boolean left = false;

	/**
	 * 控制蚂蚁调头
	 */
	public void turnRound() {
		this.direction *= -1;
	}

	/**
	 * 当蚂蚁不再会跟任何蚂蚁相遇时,控制蚂蚁直接离开木杆
	 */
	public void leave() {
		if (this.direction == Direction.LEFT) {
			crawlingTime += position / speed;
		} else {
			crawlingTime += (1 - position) / speed;
		}
		nextMeetingTime = Double.MAX_VALUE;
		left = true;
	}

	/**
	 * 控制蚂蚁爬行一段时间(前提在此段时间内不会和任何蚂蚁相遇)
	 * 
	 * @param time
	 *            控制蚂蚁爬行的时间
	 */
	public 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 = Double.MAX_VALUE;
	}

	/**
	 * 计算和另一只蚂蚁相遇的时间
	 * 
	 * @param ant
	 *            另一只蚂蚁
	 * @return 和另一只蚂蚁相遇的时间
	 */
	public double timeToMeet(Ant ant) {
		if (this.direction * ant.getDirection() > 0) {
			return Double.MAX_VALUE;
		}

		if (this.direction == Direction.LEFT && this.getPosition() <= ant.getPosition()
				|| this.direction == Direction.RIGHT && this.getPosition() >= ant.getPosition()) {
			return Double.MAX_VALUE;
		}

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

	public double getCrawlingTime() {
		return crawlingTime;
	}

	public void setCrawlingTime(double crawlingTime) {
		this.crawlingTime = crawlingTime;
	}

	public boolean isLeft() {
		return left;
	}

	public void setLeft(boolean left) {
		this.left = left;
	}

	public double getPosition() {
		return position;
	}

	public void setPosition(double position) {
		this.position = position;
	}

	public double getDirection() {
		return direction;
	}

	public void setDirection(double direction) {
		this.direction = direction;
	}

	public double getSpeed() {
		return speed;
	}

	public void setSpeed(double speed) {
		this.speed = speed;
	}

	public double getNextMeetingTime() {
		return nextMeetingTime;
	}

	public void setNextMeetingTime(double nextMeetingTime) {
		this.nextMeetingTime = nextMeetingTime;
	}

}
/**
 * 主程序
 */
public class Main {

	private static Main self;

	public static void main(String[] args) {
		self = new Main();
		int count = 20;
		List<Ant> ants;
		double crawlingTime, maxCrawlingTime = 0;
		for(int i = 0; i < 1000; i++)
		{
			ants = new ArrayList<Ant>();
			self.init(ants, count);
			
			// 所有蚂蚁离开木杆的时间
			crawlingTime = self.allAntsLeftTime(ants);
			
			maxCrawlingTime = crawlingTime > maxCrawlingTime ? crawlingTime : maxCrawlingTime;
			System.out.println("Crawling Time:" + (crawlingTime * 2));
		}
		System.out.println("Max Crawling Time:" + (maxCrawlingTime * 2));
	}
	
	/**
	 * 计算所有蚂蚁离开木杆的耗时
	 * 
	 * @param ants 所有蚂蚁
	 * @return 所有蚂蚁离开木杆的耗时
	 */
	private double allAntsLeftTime(List<Ant> ants)
	{
		double nextMeetingTime;
		// 若木杆上的蚂蚁可能相遇,则控制蚂蚁持续爬行,直至不会再出现蚂蚁相遇
		while((nextMeetingTime =  nextMeeting(ants)) < Double.MAX_VALUE)
		{
			 crawling(ants, nextMeetingTime);
		}
		
		double maxCrawlingTime = 0;
		Ant ant;
		// 遍历蚂蚁在木杆上爬行的时间,获取最大值,即为所有蚂蚁离开木杆的时间
		for(int i = 0; i < ants.size(); i++)
		{
			ant = ants.get(i);
			// 若蚂蚁还未离开木杆,控制其离开
			if(!ant.isLeft())
			{
				ant.leave();
			}
			if( ant.getCrawlingTime() > maxCrawlingTime)
			{
				maxCrawlingTime = ant.getCrawlingTime();
			}
		}
		return maxCrawlingTime;
	}
	
	/**
	 * 控制所有蚂蚁爬行一段时间(前提:在这个时间段内,所有蚂蚁都不会相遇)
	 * 
	 * @param ants 所有蚂蚁
	 * @param time 爬行时间
	 */
	private void crawling(List<Ant> ants, double time)
	{
		Ant ant;
		for(int i = 0; i < ants.size(); i++)
		{
			ant = ants.get(i);
			if(ant.isLeft())
			{
				continue;
			}
			
			// 若当前蚂蚁不会再和任何蚂蚁相遇,控制其离开,计算爬行时间
			if(ant.getNextMeetingTime() == Double.MAX_VALUE)
			{
				ant.leave();
				continue;
			}
			
			ant.crawling(time);
			if(ant.getNextMeetingTime() == time)
			{
				ant.turnRound();
			}
		}
	}

	/**
	 * 计算下一次出现蚂蚁相遇事件的时间
	 * 
	 * @param ants 所有蚂蚁
	 * @return 下一次出现蚂蚁相遇事件的时间
	 */
	private double nextMeeting(List<Ant> ants) {
		Ant ant1, ant2;
		double timeToMeet;
		// 计算每只蚂蚁与其他蚂蚁相遇的最短时间
		// 已离开木杆的蚂蚁不会再和任何蚂蚁相遇
		for (int i = 0; i < ants.size(); i++) {
			ant1 = ants.get(i);
			
			// 若蚂蚁1已离开木杆,则无需计算
			if(ant1.isLeft())
			{
				continue;
			}
			// 计算蚂蚁1与其他蚂蚁相遇的最短时间
			for (int j = i + 1; j < ants.size(); j++) {
				ant2 = ants.get(j);
				
				// 若蚂蚁2已离开木杆,则无需计算
				if(ant2.isLeft())
				{
					continue;
				}
				timeToMeet = ant1.timeToMeet(ant2);
				if (timeToMeet == Double.MAX_VALUE) {
					continue;
				}

				// 若两只蚂蚁可以相遇,且相遇时间短于当前最小时间,则刷新起下次相遇时间
				if (ant1.getNextMeetingTime() > timeToMeet) {
					ant1.setNextMeetingTime(timeToMeet);
				}
				if (ant2.getNextMeetingTime() > timeToMeet) {
					ant2.setNextMeetingTime(timeToMeet);
				}
			}
		}
		
		// 获取下一次出现蚂蚁相遇的时间点(发生在多久以后)
		double nextMeetTime = Double.MAX_VALUE;
		for(int i = 0; i < ants.size(); i++)
		{
			if(ants.get(i).getNextMeetingTime() < nextMeetTime)
			{
				nextMeetTime = ants.get(i).getNextMeetingTime();
			}
		}
		return nextMeetTime;
	}

	/**
	 * 初始化所有蚂蚁的状态
	 * 
	 * @param ants 蚂蚁对象数组
	 * @param count 蚂蚁数量
	 */
	private void init(List<Ant> ants, int count) {
		Ant ant;
		for (int i = 0; i < count; i++) {
			ant = new Ant();
			ant.setPosition(Math.random());
			ant.setDirection((Math.random() > 0.5 ? 1 : -1));
			ants.add(ant);
		}
	}

}

 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值