在铁人三项比赛中为团队实现最佳完成时间的算法[关闭]
Posted
技术标签:
【中文标题】在铁人三项比赛中为团队实现最佳完成时间的算法[关闭]【英文标题】:Algorithm for achieving best finish time for a team in a triathlon race [closed] 【发布时间】:2015-02-21 16:52:23 【问题描述】:老师计划一场比赛,每位参赛者必须完成 20 圈的游泳,然后是 10 公里的自行车,然后是 3 公里的跑步。例如 换句话说,第一个参赛者游完 20 圈,下车,开始骑自行车。第一个人一离开游泳池,第二个参赛者就开始游 20 圈;当他或她出去并开始骑自行车时,第三名参赛者开始游泳。 . .等等
每个参赛者都有一个预计的游泳时间是指完成 20 圈游泳的预计时间,每个参赛者也有预计的骑行和跑步时间。问题是为比赛设计一个时间表,即参赛者开始的顺序。参与者可以同时骑自行车和比赛,但池中最多只有一个人。
问题:设计一种高效的算法来调度上述任务? 还有一个证明算法正确的程序。
尝试的解决方案: 我想出了这个主意: 将参赛者从1初始化到n, 设 si, bi, ri 表示游泳、骑自行车和跑步时间的选手 i 。 我们按照循环所用时间+跑步所用时间的递减顺序排列参赛者,并按此顺序发送。 我无法正确制定算法和程序,因此需要帮助。
【问题讨论】:
如果您想按所需时间对它们进行排序,请考虑使用 PriorityQueue,它可以让您以最快的时间获得下一个人。 您需要什么帮助?您能否发布到目前为止您尝试过的伪代码或实际的 Java 代码,以及您在哪里卡住了?否则,看起来您只是在要求人们为您完成这项任务。 【参考方案1】:你只需要担心两个简单的规则:
-
如果我们让花最少时间游泳的参赛者先游泳,我们将缩短参赛者之间的完成时间。
如果两名选手的游泳时间相同怎么办?在这种情况下,应先派出总跑步+骑行时间较多的参赛者,以便他们在剩余的活动中抢占先机。
考虑每位参赛者在特定活动上花费的时间:
Contestant->Swim time(mins)->Run time(mins)->Cycle time(mins)
A->1->1->1
B->2->1->1
C->1->1->1
案例 1: 游泳时间最长的选手先行。比赛从下午 12:00 开始,按照 B、A、C 的顺序,我们有:
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: 游泳时间最长的选手排名第二。比赛从下午 12:00 开始,按照 A、B、C 的顺序,我们有:
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:00 开始,我们有 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());
请注意,Contestant 类包含一个 Map。此地图的目的是允许您为参赛者添加任意数量的任务,而无需更改代码。键代表游泳等活动,值(整数)代表相应活动的时间。
【讨论】:
代码的时间复杂度是O(n^2)。 我是这么想的——如果有 n 位参赛者,那么我们将一直到最后 n 位来选择截止日期最早的人。这个循环将运行 n 次。我猜我的错在第一次去 T.C 将是 O(n) 哎呀,对不起,我不知道实际上我的笔记本电脑在这个网站上被冻结了,并且在当时随意点击它一定发生了,而且我是网站界面的新手,所以它需要是时候让我习惯了, 非常感谢您的时间和努力,虽然我对您的程序有一些疑问 我没有得到这部分代码的作用?否则 int P1TimeExceptSwimming = 0; int P2TimeExceptSwimming = 0; for(String activity : one.getTimings().keySet()) if(!activity.equals("Swimming")) P1TimeExceptSwimming+=one.getTimeFrame(activity); for(String activity : two.getTimings().keySet()) if(!activity.equals("Swimming")) P2TimeExceptSwimming+=two.getTimeFrame(activity); if(P1TimeExceptSwimming>P2TimeExceptSwimming) return -1;【参考方案2】:这是一个贪婪编程的明显案例(注意:贪婪并非总是最佳选择): 我在这里假设您希望尽量减少总时间,因为这里没有提到。
算法:
设 si、bi、ri 分别表示游泳、骑自行车和跑步时间的选手 i。
按参赛者完成所有三项任务所需的时间排序,按降序排列。
根据步骤 2 中的顺序安排它们
对参赛者进行排序:
计算每个人游泳、骑车和跑步所需的时间。
将这些时间相加,并按降序排列。
【讨论】:
这真的不像按总时间的降序排序那么简单。看我的回答。 它的贪婪方法,不确定它是否是最优的。但是我在这里做的是最慢的选手应该先送出去,以此类推,最快的选手应该最后送出去,因为他可以覆盖其他选手。在你的方法中,如果游泳时间最少的选手最后出局,但如果他的骑行和跑步时间非常非常大怎么办。你最终会增加总时间。所以在我看来,考虑到总时间会很好。 @bot 如果有 2 位参赛者 (10,10,10) 和 (9,20,30) 采用您的方法,您将发送第一个参赛者,因此当他在 10 点后完成游泳时,您将发送下一位参赛者。总时间:10 + 9 + 20 + 30 = 69 个单位,我会先发送参赛者 2:使用我的方法 总时间:9 + 20 + 30 = 59 个单位 这里有一个基本限制:The参与者可以同时骑自行车和比赛,但池中最多只有一个人。 我会先发送 9,20,30,然后再发送 10,10,10。看来你不明白我的做法。 @bot 好的,如果时间是 .. (9,10,10) & (10,20,30).. 使用您的方法将需要 9+ 10 + 20 + 30 = 69和我的方法需要10 + 20 + 30 = 60,顺便说一句,我不是来证明我的方法是对还是错,或者证明你的方法的任何事情。我来这里是为了学习自己和帮助他人,同时也了解解决问题的不同方法。所以你想要一个输入,例如我在这里给出的。以上是关于在铁人三项比赛中为团队实现最佳完成时间的算法[关闭]的主要内容,如果未能解决你的问题,请参考以下文章