面向对象解决蚂蚁过杆问题

这里主要是讲面向对象思想解决问题,当然,数学方法也会提供,数学方法做这个题其实很简单,有点脑筋急转弯的味道。(在后面加上了第二版的面向对象的解题方案)

问题描述:

有一根27厘米的细木杆,在第3厘米、7厘米、11厘米、18厘米、23厘米这五个位置上各有一只蚂蚁。
木杆很细,不能同时通过两只蚂蚁。开始时,蚂蚁的头朝左还是朝右是任意的,
它们只会朝前走或调头,但不会后退。当任意两只蚂蚁碰头时,
两只蚂蚁会同时调头朝反方向走。假设蚂蚁们每秒钟可以走一厘米的距离。
编写程序,求所有蚂蚁都离开木杆的最小时间和最大时间。
要求:用类模拟出蚂蚁的行为特性,进而模拟出五只蚂蚁在木杆上的运行过程来编程求解。

/**
 * 思路:因为没有告诉蚂蚁的初始朝向,所以要对初始化蚂蚁朝向。 用0表示朝左,1表示朝右, 用二进制00000(0)表示五只蚂蚁都是朝向左,
 * 然后每次加1,直到加到11111(31)时。 让后随时间的推移, 有些蚂蚁可能碰头,这时就对蚂蚁的朝向就行修改,
 * 即:如原来朝向为0,则变为1,原来为1的变为0,。做到这里就会想到如何判断蚂蚁朝向问题,
 * 这个可以通过异或来解决问题。如:当要判断第一只蚂蚁朝向时,可以用二进制10000(16)与原来朝向异或,
 * 若结果为0,则表示朝向为1,朝右,否则相反;用二进制01000(8)与原来朝向异或, 可以判断第二个蚂蚁的朝向,以此类推。
 * 注意:在new一个对象数组后,还要记得对对象数组再次new,直到最后为基本类型为止。
 */

import java.util.Scanner;

public class Ant {
	boolean isLeft;// 蚂蚁的方向
	int location;// 蚂蚁的位置(0--27)

	public Ant(int location) {
		this.location = location;
	}

	public boolean isLeft() {
		return isLeft;
	}

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

	private static Scanner scanner;

	public static void main(String[] args) {
		scanner = new Scanner(System.in);
		int n = 5;// 蚂蚁个数
		// 键入蚂蚁的位置
		int count[] = new int[n];
		System.out.println("输入蚂蚁位置:");
		for (int i = 0; i < n; i++) {
			count[i] = scanner.nextInt();
		}
		Ant ant[] = new Ant[n];

		int direction = 0;// ( 0 ~ (2^n-1) )
		int maxDire = (int) (Math.pow(2, n));
		int min = Integer.MAX_VALUE;
		int max = Integer.MIN_VALUE;
		for (int i = 0; i < maxDire; i++) {// 有maxDire种方案
			for (int p = 0; p < n; p++) {// 没有保存蚂蚁的位置,所以需要重新new (也可以保存一下)
				ant[p] = new Ant(count[p]);
			}
			String bin = binaryString(direction);
			System.out.println(i + ",bin=" + bin);
			char ch[] = bin.toCharArray();
			for (int j = 0; j < n; j++) {
				ant[j].setLeft(ch[j] == '0' ? true : false);
			}
			int step = 0;// 记录步数
			boolean isIn = true;// 是否蚂蚁都掉下去了
			while (isIn) {
				isIn = false;
				step++;
				// 移动
				for (int j = 0; j < ant.length; j++) {
					if (ant[j].location > 0 && ant[j].location < 27) {
						// 0向左,1向右
						if (ant[j].isLeft) {
							ant[j].location--;
						} else {
							ant[j].location++;
						}
						isIn = true;// 如果还有走动就说明还需要继续走而不是退出(也可以计算掉下的蚂蚁数量来退出)
					}
				}
				isMeet(ant);// 碰头就掉头
			}
			System.out.println(step);
			if (step > max) {
				max = step;
			}
			if (step < min) {
				min = step;
			}
			direction++;
		}
		min--;
		max--;
		System.out.println("min=" + min + " max=" + max);
	}

	public static void isMeet(Ant ant[]) {
		// 是否碰头
		for (int j = 0; j < ant.length - 1; j++) {
			for (int k = j + 1; k < ant.length; k++) {
				if (ant[j].location == ant[k].location) {
					ant[j].setLeft(!ant[j].isLeft());
					ant[k].setLeft(!ant[j].isLeft());
				}
			}
		}
	}

	public static String binaryString(int direction) {
		String dirString = Integer.toBinaryString(direction);
		int len = dirString.length();
		for (int j = 0; j < 5 - len; j++) {
			dirString = "0" + dirString;
		}
		return dirString;
	}
}
下面提供数学方法:最短时间就是最靠近中间的蚂蚁走出去的时间,最长时间就是最靠近边缘的蚂蚁往远的一边走的时间,可以想象蚂蚁是可以穿越蚂蚁的,碰头换个方向其实就是穿过去了一样。

import java.util.Scanner;

public class Ant_Math {
	private static Scanner scanner;
	public static void main(String[] args) {
		scanner = new Scanner(System.in);
		System.out.print("输入木杆长度:");
		int len = scanner.nextInt();
		System.out.print("输入蚂蚁个数:");
		int n = scanner.nextInt();
		int[]ant = new int[n];
		int max = Integer.MIN_VALUE;
		int min = Integer.MAX_VALUE;
		int m = len;
		for (int i = 0; i < ant.length; i++) {
			ant[i] = scanner.nextInt(); 
			//最大值
			int j = 27-ant[i];
			if(j>max){
				max = j;
			}
			//最小值
			int t = Math.abs(ant[i]-len/2);
			if(t<m){
				m = t;
				min = ant[i];
			}
		}
		System.out.println("min=" + min + " max=" + max);
	}
}
//27 5 3 7 11 18 23

最后,提供一个第二版的蚂蚁过杆问题代码,这个思路比较清晰

public class Ant {
	final int LEFT_END=0;
	final int RIGHT_END=27;
	static int numOfDown;
	static int time;
	
	int pos;
	boolean left;
	boolean down;
	
	public void step(){
		if(left){
			pos--;
		}else{
			pos++;
		}
		if(pos<=LEFT_END || pos >=RIGHT_END){
			down=true;
			numOfDown++;
			
			//TODO:
			
		}
	}

	public boolean isDown() {
		return down;
	}
	public boolean isLeft() {
		return left;
	}

	public void setPos(int pos) {
		this.pos = pos;
	}

	public void turnAround() {
		left = !left;		
	}
	
	
}

public class AntRun {
	public static void main(String[] args) {
		int a[] ={3,7,11,18,23};
		int numOfDirectionStates=1;
		
		Ant ants[] = new Ant[a.length];
		for(int i=0;i<ants.length; i++){
			ants[i] = new Ant();
			numOfDirectionStates *=2;
		}
		
		boolean directionStates[][] = new boolean[numOfDirectionStates][ants.length];
		for(int i=0;i<directionStates.length;i++){
			directionStates[i][0]= (i&0x01)==1 ;
			directionStates[i][1]= (i&0x02)==2 ;
			directionStates[i][2]= (i&0x04)==4 ;
			directionStates[i][3]= (i&0x08)==8 ;
			directionStates[i][4]= (i&0x10)==16 ;
		}
		
		for(int i=0;i<directionStates.length;i++){//所有站位情况都跑一遍
			//当前这种站位情况下,所有蚂蚁数据的初始化
			for(int j=0;j<ants.length; j++){
				ants[j].setPos(a[j]);
				ants[j].left=directionStates[i][j];
				ants[j].down=false;
			}
			
			Ant.numOfDown=0;
			Ant.time=0;
			
			print(ants);//初始状态
			while(true){
				//循环的每一次即是一秒
				Ant.time++;
				
				for(int j=0; j<ants.length;j++){
					if(!ants[j].isDown()){
						ants[j].step();
					}
				}
				
				//考虑蚂蚁碰头或撞头情况
				for(int j=0;j<a.length-1;j++){
					if(!ants[j].isLeft() && ants[j+1].isLeft() &&
							!ants[j].isDown() && !ants[j+1].isDown()){
						//碰头
						if(ants[j].pos==ants[j+1].pos){
							System.out.println("出现碰头,掉头走");
							ants[j].turnAround();
							ants[j+1].turnAround();
						}
						
						//撞头
						if(ants[j].pos>ants[j+1].pos){
							System.out.println("出现撞头,回退到原地,掉头走");
							ants[j].turnAround();
							ants[j+1].turnAround();
							ants[j].step();
							ants[j+1].step();
						}
					}
				}
				
				
				print(ants);//输出5只蚂蚁的位置信息
				if(Ant.numOfDown==ants.length){
					System.out.println("全离掉下去了...................");
					break;
				}
			}
		}
		
		
	}
	
	//输出5只蚂蚁的位置信息
	public static void print(Ant ants[]){
		for(int i=0;i<ants.length-1;i++){
			System.out.print(ants[i].pos+",");
		}
		System.out.println(ants[ants.length-1].pos);
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值