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

问题描述:

有一根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);
}
}