最近在准备校招的事情,顺便做一下各名企的笔试题,题还是挺有意思的,下面是百度的一道典型笔试题解答。
1
|
题目:有一根27厘米的细木杆,在第3厘米、7厘米、11厘米、17厘米、23厘米这五个位置上各有一只蚂蚁。木杆很细,不能同时通过一只蚂蚁。开始时,蚂蚁的头朝左还是朝右是任意的,它们只会朝前走或调头,但不会后退。当任意两只蚂蚁碰头时,两只蚂蚁会同时调头朝反方向走。假设蚂蚁们每秒钟可以走一厘米的距离。编写程序,求所有蚂蚁都离开木杆的最小时间和最大时间。
|
答案为:最小为11秒,最大为24秒。
该问题主要考查问题分析能力、编程能力,更侧重编程能力。
一、分析方面
很显然是求最小距离和最大距离的问题,只不过中间带有行走的碰撞后调整方向,加大了复杂度。
分析到此为止,其实就可以了。只要考虑如何把变化可能性程序化去计算就可以了。
二、编程方面
前后我试着分析了3小时左右吧,其实最后也没分析清楚,当我动手编程的时候,很快就有思路,整个实现、测试、优化用了20分钟左右,就全部搞定了。有些时候,只靠单纯分析,不如边分析边实现,反而会事办功倍。下面附上全部代码,共2个类,约200行代码:
(1)面向对象编程之蚂蚁类的封装Ant.java
|
(2) 面向对象编程之业务处理类的封装,也包括了main方法中的测试代码段
|
|
package test;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import pojos.Ant;
public class TestAntOutQuestion {
public static int directionList[][] = null;
public static int time_size = 0;
public static int all_ant_num = 0;// 每次比较的起始方向值,只有+1,-1,代表正反两方向
public static List<Integer> x_position_list = null;
public static List<Ant> remove_ant_list = new ArrayList<Ant>();
//计算初始化
public static void init(List<Integer> init_x_position_list) {
System.out.println("蚂蚁个数为---" + init_x_position_list.size());
System.out.println("初始位置序列为---" + init_x_position_list);
x_position_list = init_x_position_list;
int ant_num = x_position_list.size();
all_ant_num = ant_num;
int sum_time = 1;
for (int i = 0; i < ant_num; i++) {
sum_time *= 2;
}
directionList = new int[sum_time][ant_num];
time_size = directionList.length;// 32次
// ant_num = directionList[0].length;// 每次比较的起始方向值,只有+1,-1,代表正反两方向
String temp = null;// 存放0-31的二进制数
char char_array[] = null;// 存放打散的int集合
for (int i = 0; i < time_size; i++) {
temp = getFixString(ant_num, i);
char_array = temp.toCharArray();
int arr_len = char_array.length;
for (int j = 0; j < arr_len; j++) {
if (char_array[j] == '0') {
directionList[i][j] = -1;
} else {
directionList[i][j] = 1;
}
}
}
}
// 得到最小用时
public static int getMinTime(int unsign_speed, int under_x_postion,
int extra_x_postion) {
List<Integer> list = getAllTime(unsign_speed, under_x_postion,
extra_x_postion);
Collections.sort(list);
return list.get(0);
}
// 得到最大用时
public static int getMaxTime(int unsign_speed, int under_x_postion,
int extra_x_postion) {
List<Integer> list = getAllTime(unsign_speed, under_x_postion,
extra_x_postion);
Collections.sort(list);
return list.get(list.size() - 1);
}
// 得到所有情况下的用时
public static List<Integer> getAllTime(int unsign_speed,
int under_x_postion, int extra_x_postion) {
List<Integer> timeList = new ArrayList<Integer>();// 存放最后的时间集合
List<Ant> ant_list = new ArrayList<Ant>(5);// 存放每个节点的ant对象
int temp_count = 0;
// 给5个蚂蚁分别给方向值,共32个搭配
for (int[] one_time : directionList) {// one_time.length=ant_num
Ant ant_temp = null;
for (int index = 0; index < all_ant_num; index++) {
ant_temp = new Ant(unsign_speed, x_position_list.get(index),
under_x_postion, extra_x_postion);
ant_temp.setDirection(one_time[index]);
ant_list.add(ant_temp);
}
int begin = 0;
processConflict(ant_list);// 首先处理一次冲突
while (!isEnd(ant_list)) {
// System.out.println(ant_list);
// 去除已经走出的ant
removeOverAnt(ant_list);
allRunOnce(ant_list);
processConflict(ant_list);
begin++;
}
temp_count++;
timeList.add(begin);
// System.out.println(begin);
}
return timeList;
}
/**
* 判断所有的蚂蚁是否都已经离开
*
* @param antList
* @return
*/
public static boolean isEnd(List<Ant> antList) {
boolean isExist = true;
for (Ant ant : antList) {
if (ant.isOut()) {
remove_ant_list.add(ant);
} else {
isExist = false;
}
}
return isExist;
}
/**
* 删除掉所有的已经out的节点的ant
* @param antList
*/
public static void removeOverAnt(List<Ant> antList) {
for (Ant ant : remove_ant_list) {
antList.remove(ant);
}
remove_ant_list.clear();
}
/**
* 所有ant均走1cm
* @param antList
*/
public static void allRunOnce(List<Ant> antList) {
for (Ant ant : antList) {
ant.runOnce();
}
}
/**
* 处理冲突,若有则处理没有则算了 只会出现两两的冲突,不会有两个以上的 ant同时发生冲突
* 解决完一次冲突后,有可能会产生次生冲突,故要循环节点集合是否产生冲突,直到集合都无任何冲突则该向方法执行完成
* @param antList
*/
public static void processConflict(List<Ant> antList) {
int len = antList.size();
while (isFindConflict(antList)) {// 循环处理冲突,直到没有任何的conflict
for (int i = 0; i < len - 1; i++) {
if (isConflict(antList.get(i), antList.get(i + 1))) {
solveConflict(antList.get(i), antList.get(i + 1));
}
}
}
}
// 发现节点集合中是否有冲突产生
public static boolean isFindConflict(List<Ant> antList) {
int len = antList.size();
for (int i = 0; i < len - 1; i++) {
if (isConflict(antList.get(i), antList.get(i + 1))) {
return true;
}
}
return false;
}
// 解决两ant冲突,直接变向
public static void solveConflict(Ant ant_1, Ant ant_2) {
ant_1.setDirection(ant_1.getDirection() * -1);
ant_2.setDirection(ant_2.getDirection() * -1);
}
// 判断两ant是否冲突,1是要对向,2是两者x_postion+this.speed*this.direction有交叉处
public static boolean isConflict(Ant ant_1, Ant ant_2) {
if ((ant_1.getDirection() != ant_2.getDirection())
&& ((ant_1.getX_position() + ant_1.getSpeed()
* ant_1.getDirection() == ant_2.getX_position()) || (ant_2
.getX_position()
+ ant_2.getSpeed() * ant_2.getDirection() == ant_1
.getX_position()))) {
return true;
}
return false;
}
// 得到指len相应的数字的二进制字符串表示形式
public static String getFixString(int fix_length, int value) {
String temp = Integer.toBinaryString(value);
int temp_len = temp.length();
for (int i = temp_len; i < fix_length; i++) {
temp = "0" + temp;
}
return temp;
}
public static void main(String[] args) {
// 给出初始状态位置集合
List<Integer> x_position_list = new ArrayList<Integer>();
x_position_list.add(3);
x_position_list.add(7);
x_position_list.add(11);
x_position_list.add(17);
x_position_list.add(23);
// //>5的部分了
// x_position_list.add(12);
// x_position_list.add(13);
// x_position_list.add(14);
// x_position_list.add(15);
x_position_list.add(25);
x_position_list.add(24);
// x_position_list.add(26);
Collections.sort(x_position_list);// 先排下序
init(x_position_list);
int all_length=27;
System.out.println("min time---" + getMinTime(1, 0, all_length));
System.out.println("max time---" + getMaxTime(1, 0, all_length));
}
}
希望对后来的同学们有帮助。