在铁人三项比赛中为团队实现最佳完成时间的算法

时间:2015-02-21 16:52:24

标签: java algorithm

老师计划比赛,每位参赛者必须完成20圈游泳,然后骑行10公里,然后跑3公里。例如,换句话说,第一个参赛者在20圈游泳,下车,并开始骑自行车。第一个人离开游泳池后,第二个参赛者开始游泳20圈;一旦他或她开始骑自行车,第三名选手开始游泳。 。 。等等

每位参赛者的预计游泳时间是指完成20圈游泳的预计时间,每位参赛者都有预计的骑行和跑步时间。问题是设计种族的时间表,以及对参赛者的开始进行排序的顺序。参与者可以同时骑自行车和比赛,但最多只有人可以在游泳池中。

问题:设计一个有效的算法来安排上述任务?     另外一个证明算法正确的程序。

尝试解决方案: 我想出了这个想法: 将参赛者从1到n初始化, 让si,bi,ri表示游泳,骑自行车和跑步时间的选手i。 我们按照循环时间的递减顺序排列参赛者+运行时间并按此顺序发送。 我不能正确地制定算法和程序,所以需要帮助。

2 个答案:

答案 0 :(得分:3)

您只需要担心两个简单的规则:

  1. 如果我们派出花费最少时间游泳的选手,我们将减少参赛者之间的完成时间。
  2. 如果两名参赛者有相同的游泳时间怎么办?在这种情况下,应首先发送总跑步+骑行时间较长的参赛者,以便他们能够在剩下的活动中抢占先机。
  3. 考虑每位参赛者参加特定活动的时间:

    Contestant->Swim time(mins)->Run time(mins)->Cycle time(mins)
    A->1->1->1
    B->2->1->1
    C->1->1->1
    

    案例1: 游泳时间最长的参赛者先行。比赛从B,A,C顺序的中午12:00开始,我们有:

    Swimming complete->Running complete->Cycling complete
    B->12:02->12:03->12:04
    A->12:03->12:04->12:05
    C->12:04->12:05->12:06
    

    案例2: 游泳时间最长的参赛者排名第二。比赛从A,B,C的顺序在中午12:00开始,我们有:

    Swimming complete->Running complete->Cycling complete
    A->12:01->12:02->12:03
    B->12:03->12:04->12:05
    C->12:04->12:05->12:06
    

    案例3: 游泳时间最长的参赛者排名第三。比赛从中午12点开始,按照A,C,B的顺序开始:

    Swimming complete->Running complete->Cycling complete
    A->12:01->12:02->12:03
    C->12:02->12:03->12:04
    B->12:04->12:05->12:06
    

    你可以看到,在所有情况下,最后一名选手在12:06完成比赛。然而,在案例1(游泳时间最长的参赛者)中,第一个参赛者在下午12:04结束,第二个参赛者在12:05结束。如果是第二名(参赛者最大游泳时间排在第二位),第一名选手将在12:03完成比赛,第二名选手将在12:05完成比赛。在案例3(最大游泳时间的参赛者排名第三)中,第一个参赛者在12:03结束比赛,第二个参赛者在12:04结束比赛。这是迄今为止最有效的订单,因为到12点04分,你已经有两位参赛者完成了比赛。

    但是,如果两个参赛者有相同的游泳时间但不同的周期和运行时间会怎样。考虑一下:

    Contestant->Swim time(mins)->Run time(mins)->Cycle time(mins)
    A->1->1->1
    B->2->2->1
    C->2->1->1
    

    案例4 :在游泳时间相同的两名参赛者中,参赛者的骑行和跑步时间总和较低:

    Swimming complete->Running complete->Cycling complete
    A->12:01->12:02->12:03
    C->12:03->12:04->12:05
    B->12:05->12:07->12:08
    

    案例5:在游泳时间相同的两位参赛者中,参赛者的骑行和跑步时间总和最高:

    Swimming complete->Running complete->Cycling complete
    A->12:01->12:02->12:03
    B->12:03->12:05->12:06
    C->12:05->12:06->12:07
    

    可以看出,最后一名选手在第4组时间下午12:08完成比赛,而最后一名选手在第5组中以12:07结束比赛。这意味着如果两名选手拥有相同的游泳时间,骑自行车+跑步时间较长的选手应先行。

    用Java编写代码:

    首先创建一个类来保存参赛者信息:

    public class Contestant {
        private String name;
        private Map<String,Integer> timings = new HashMap<>();
    
        public Contestant(String name, Map<String, Integer> timings) {
            this.name = name;
            this.timings = timings;
        }
    
        public Integer getTimingFor(String activity) {
            return timings.get(activity);
        }
    
        public Map<String, Integer> getTimings() {
            return timings;
        }
    
        public String getName() {
            return name;
        }
    
    
    }
    

    然后创建一个比较器,决定哪个参赛者应该在另一个参赛者之前。这个想法是按照游泳时间(升序)的顺序命令参赛者,然后按剩余活动的顺序(降序)命令

      public class ContestantComparator implements Comparator<Contestant> {
    
        @Override
        public int compare(Contestant one, Contestant two) {
            int contestantOneSwimTime = one.getTimingFor("Swimming");
            int contestantTwoSwimTime = two.getTimingFor("Swimming");
    
            if(contestantOneSwimTime<contestantTwoSwimTime) {
                return -1;
            } else if(contestantOneSwimTime>contestantTwoSwimTime) {
                return 1;
            } else {
                int c1RemainingTimeExceptSwimming = 0;
                int c2RemainingTimeExceptSwimming = 0;
    
                for(String activity : one.getTimings().keySet()) {
                    if(!activity.equals("Swimming")) {
                        c1RemainingTimeExceptSwimming+=one.getTimingFor(activity);
                    }
                }
    
                for(String activity : two.getTimings().keySet()) {
                    if(!activity.equals("Swimming")) {
                        c2RemainingTimeExceptSwimming+=two.getTimingFor(activity);
                    }
                }
    
                if(c1RemainingTimeExceptSwimming>c2RemainingTimeExceptSwimming) {
                    return -1;
                } else if(c1RemainingTimeExceptSwimming<c2RemainingTimeExceptSwimming) {
                    return 1;
                } else {
                    return 0;
                }
            }
        }
    }
    

    使用代码的主类:

    public class Contest {
    
        public static void main(String []args) {
            Map<String,Integer> timings = new HashMap<String,Integer>();
            timings.put("Swimming", 1);
            timings.put("Running", 1);
            timings.put("Cycling", 1);
            Contestant a = new Contestant("A",timings);
    
            timings = new HashMap<String,Integer>();
            timings.put("Swimming", 1);
            timings.put("Running", 2);
            timings.put("Cycling", 1);
            Contestant b = new Contestant("B",timings);
    
            timings = new HashMap<String,Integer>();
            timings.put("Swimming", 1);
            timings.put("Running", 2);
            timings.put("Cycling", 2);
            Contestant c = new Contestant("C",timings);
    
            List<Contestant> contestants = new ArrayList<Contestant>();
            contestants.add(a);
            contestants.add(b);
            contestants.add(c);
            Collections.sort(contestants,new ContestantComparator());
    
            for(Contestant contestant : contestants) {
                System.out.println(contestant.getName());
            }
    
        }
    
    }
    

    请注意,参赛者课程包含地图。此映射的目的是允许您为参赛者添加任意数量的任务,而无需更改代码。键表示游泳等活动,值(整数)表示相应活动的时间。

答案 1 :(得分:-1)

这是一个贪婪编程的明显案例(注意:贪婪总是不是最佳选择): 我在这里假设您希望最小化总时间,因为这里没有提到。

算法:

  1. 让si,bi,ri表示游泳,骑自行车和跑步时间的选手i。

  2. 在完成所有三项任务时,对参赛者进行排序,按降序对其进行排序。

  3. 根据步骤2中的顺序安排它们

  4. 对参赛者进行排序:

    1. 计算每个人游泳,骑车和跑步所需的时间。

    2. 添加这些时间,并按降序排序。