跑马问题

64匹马,8个赛道,找出跑得最快的4匹马,至少比赛几场?
下面是我对这道题的理解,借用了64匹马,8个赛道问题的帖子。
相信这个问题不少同学在面试过程中遇到过。这题是道智力题,我们应该通过画图的方式来实现。我们知道油64匹马,8个跑道,那么根据贪心思想,我们应该让所有马都上跑道,这样跑8次,可以淘汰一半的马。如下图所示:
在这里插入图片描述

我们得到每组的前四名,共计8 * 4 = 32匹,接下来我们应该怎么做呢,4匹4匹的荷载一起,四个跑道比4次吗?答案是否定的,这样等于没有利用每个赛道的4匹之间的先后属性,我们应该使用每个赛道的头名进行比赛,这样只需要比一次就可以淘汰一半的马。这时候总冠军已经诞生,他就是头名比赛中还是头名的那一匹。
在这里插入图片描述
接下来我们得从剩下得15匹中选择3匹,我们在比赛之前,先分析一下现在得情况,对于剩下得15匹,第一名所在得那一条赛道剩下的马是不是都有可能,第二名所在的赛道的最后一匹是不可能入选的,第三名所在的赛道的最后两匹也是不可能入选的,以此类推,最后我们只需要比较剩下的9匹即可。我们通过随机选择8匹,然后获得前3匹,与剩下的一匹组合4匹再跑一次,选出剩下3匹。
在这里插入图片描述

综上所述,总共需要11次比赛就能得出前4匹最快的马。
以下是代码模拟过程,我们先建立一个horse类,包含两个属性,编号和速度。通过随机生成速度的方式,生成64匹速度不同的马作为测试用例,然后经过上述算法模拟输出,与直接排序法进行比较,验证结论。
我们将赛道和马都变量化,这样可以测试16个赛道,4匹马等多种情况。

import java.util.ArrayList;
import java.util.List;
import java.util.PriorityQueue;

/**
 * 64匹马,8个赛道,找出跑得最快的4匹马,至少比赛几场?
 * 每个赛道最多容纳8匹马同时跑
 * @author brooke
 *
 */
public class fastHorses {
	
	Horse[] horses;

	public fastHorses(int n, int speed) {
		this.horses = generateHorse(n, speed);
	}

	/**
	 * 生成n匹马,speed表示马的速度范围(不是实际的马速度)
	 * @param n
	 * @param speed
	 * @return
	 */
	public Horse[] generateHorse(int n, int speed) {
		Horse[] horses = new Horse[n];
		List<Horse> list = new ArrayList<>();
		for(int i=0;i<n;i++) {
			horses[i] = new Horse(i + 1, (int)(Math.random() * speed) + 1);
			list.add(horses[i]);
		}
		list.sort((o1, o2)->{return o2.speed - o1.speed;});
		for(int i=0;i<list.size();i++) {
			System.out.print(list.get(i));
		}
		System.out.println();
		return horses;
	}
	
	/**
	 * 获取最终的target匹最快的马需要的最少比较次数
	 * @param capacity 是赛道容量
	 * @param target
	 * @return
	 */
	public int getMinCompares(int capacity, int target) {
		if(capacity < target) {
			System.out.println("Input invalid!");
			return -1;
		}
		if(horses.length % capacity != 0) {
			System.out.println("暂不支持!");
			return -2;
		}
		List<List<Horse>> lists = new ArrayList<>();
		List<Horse> list = new ArrayList<>();
		int num = 0;
		int cnt = 0;
		//第一次,每8匹一组,选出前4匹,共比赛8次
		for(int i=0;i<horses.length;i++) {
			if(cnt++ < capacity) {
				list.add(horses[i]);
			} else {
				num++;
				lists.add(HorseCompitition(list, target));
				list = new ArrayList<>();
				cnt = 0;
				i--;
			}
		}
		num++;
		lists.add(HorseCompitition(list, target));
		list = new ArrayList<>();
		cnt = 0;
		//第二次,每组第一名开始比较,选出前4匹
		List<Horse> temp = null;
		for(int i=0;i<lists.size();i++) {
			list.add(lists.get(i).get(0));
		}
		num++;
		temp = HorseCompitition(list, target);
		list = new ArrayList<>();
		List<Horse> res = new ArrayList<>();
		res.add(temp.get(0));//找到最快的一匹
		for(int i=0;i<lists.size();i++) {
			Horse horse = lists.get(i).get(0);
			if(!temp.contains(horse)) {
				lists.remove(i--);
			}
		}
		//16匹要淘汰6匹(推导),然后最快的一匹已经选出,剩余9匹,采用随机选择8匹参与比赛
		//然后取前3匹与剩下的一匹比赛,选出最后的3匹,加上最快的一匹就是答案
		for(List<Horse> horses : lists) {
			int num1 = target - temp.indexOf(horses.get(0));
			for(int i=0;i<num1;i++) {
				list.add(horses.get(i));
			}
		}
		list.remove(res.get(0));
		int tempindex = (int)(Math.random() * list.size());
		Horse temphorse = list.get(tempindex);
		list.remove(tempindex);
		num++;
		list = HorseCompitition(list, target - 1);
		list.add(temphorse);
		num++;
		list = HorseCompitition(list, target - 1);
		res.addAll(list);
		for(Horse horse : res)
			System.out.print(horse);
		return num;
	}
	
	/**
	 * 从list中选出前target个返回(模拟比赛)
	 * @param list
	 * @param target
	 * @return
	 */
	private List<Horse> HorseCompitition(List<Horse> list, int target){
		if(list.size() < target) {
			return list;
		}
		List<Horse> res = new ArrayList<>();
		if(target <= 0) {
			return res; 
		}
		PriorityQueue<Horse> queue = new PriorityQueue<>((o1, o2)->{return o1.speed - o2.speed;});
		for(int i=0;i<list.size();i++) {
			if(queue.size() < target) {
				queue.add(list.get(i));
			}else {
				if(list.get(i).speed > queue.peek().speed) {
					queue.poll();
					queue.add(list.get(i));
				}
			}
		}
		while(!queue.isEmpty()) {
			res.add(0, queue.poll());
		}
		return res;
	}
	
	public static void main(String[] args) {
		fastHorses test = new fastHorses(64, 100);
		System.out.println("\nthe min compares is " + test.getMinCompares(8, 4));
	}
}

class Horse{
	int id; // 马的编号
	int speed; // 马的速度值
	
	public Horse(int id, int speed) {
		super();
		this.id = id;
		this.speed = speed;
	}

	@Override
	public String toString() {
		return "Horse [id=" + id + ", speed=" + speed + "]";
	}
}

测试结果:
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值