如何解决贪婪算法,以最大化得分
我正在尝试在Java中实现一个方法,该方法将具有截止日期,得分和对象编号的对象的ArrayList作为输入。每个都可以通过以下方式访问:
game.get(i).number
game.get(i).score
game.get(i).deadline
其中game
是ArrayList,i
是索引。
在考虑每场比赛的截止日期的同时,我想最大化得分。每场比赛必须在截止日期之前完成。例如如果截止日期为5,则必须在4或更早之前完成。
例如,这是一个示例ArrayList,其相应数据按照得分值的降序排列:
Index Game number score Deadline
0 3 76 3
1 4 66 2
2 1 52 2
3 6 51 4
4 5 47 2
5 2 23 1
然后可能是以下ArrayList:
maximizedscore = [4,1,3,6]
->这里的每个索引代表小时。即使游戏3的得分高于游戏4和游戏1的得分,我们也将游戏4的索引设为0,将游戏1的索引设为1,因为它们的截止日期均为2,因此必须在此之前完成。但是,游戏3的截止日期为3,因此我们可以在第二小时进行,以使总分最大化。请注意,第5场的最后期限与第4场和第1场的期限相同,但是积分少于这两者,因此我们将其牺牲。
编辑:每个索引(0,2,4,..)代表小时,而索引处的值代表该小时完成的游戏编号。
编辑2:我们每小时只能进行一场比赛。因此,如果数据中的最新截止日期为x,则我们最多可以进行x次游戏。即在此示例中为4。
这提供了最高245分。
游戏的顺序并不重要,只要它们在截止日期之前即可。例如:[1,4,6]
也可以接受,因为游戏4和游戏1都在截止日期之前完成。
不幸的是,我不知道如何实现这一目标。希望我对我的需求有一个清晰的认识。
感谢您的帮助!
解决方法
首先要做的是按照游戏的得分对游戏进行排序,因为我们希望游戏的得分最高:
如果您有ArrayList
个对象,说ArrayList<Game> inputData = new ArrayList<>();
,则可以在Java中将其排序:
inputData.sort(Comparator.comparing(Game::getScore));
现在最低分是第一,最高分是最后。
由于我们必须跟踪截止日期,因此我将它们放入单独的ArrayList
中,并在需要时将它们逐个删除:
ArrayList<Integer> deadlines = new ArrayList<>();
for(Game game : inputData) {
if (!deadlines.contains(game.deadline))
deadlines.add(game.deadline);
}
此后,我们的想法是一个一个地遍历inputData
并跟踪previousDeadline
和currentDeadline
。如果我们认为currentDeadline
比previousDeadline
大,那就意味着我们不能接受在此之前的任何截止日期。可以通过检查我们之前创建的deadlines
列表并从中删除截止日期来完成。
int previousDeadline = -1; // initial value because there is no -1 deadline
for(int i = inputData.size()-1; i >= 0; i--) {
int currentDeadline = inputData.get(i).deadline;
// compare previous and currentDeadline and remove from deadlines list
if(previousDeadline != -1 && previousDeadline < currentDeadline) {
for(int j = 1; j < currentDeadline; j++) {
deadlines.remove(Integer.valueOf(j));
}
}
// add to result only if present in deadlines list and update previous deadline
if (deadlines.contains(currentDeadline) ) {
result.add(inputData.get(i).number);
previousDeadline = inputData.get(i).deadline;
}
}
如果您输入的内容是您提供的,您将获得带有[3,4,1,6]
我将尝试给出一种通用方法,而无需编写任何代码。
我将把您正在寻找的结果称为“时间表”。正如您在问题中所解释的那样,您可以在日程表中放置的最大游戏数由输入数据的“截止日期”列中的最大值表示。我将其称为“时间限制”。
您要的是贪婪算法。这样的算法将生成并检查所有游戏时间表,以找到使您的得分最大化的游戏时间表。
基本方法
您可以采用的最基本方法是生成“时限”或更短长度的所有游戏排列。对于其中的每一个,您都需要检查:
- 这确实是一个有效的时间表吗?(暂定时间表中的每个游戏在放置时都应付款吗?)
- 该暂定时间表的总成绩是否大于迄今为止获得的最佳成绩?如果是这样,您可以“保留”该解决方案,然后继续尝试其他时间表
第一种方法的主要困难是正确生成所有可能的时间表。即:
- 0
- 0 1
- 0 1 2
- 0 1 2 3
- 0 1 2 3 4
- 0 1 2 4
- 0 1 2 4 3
- 0 1 3
- ....
- 1
- 1 0
- 1 0 2
- ....
优化
现在,上述基本方法存在一些不足之处。例如,当您在构建可能的时间表时,由于截止日期标准,您将构建一个不可能的时间表。例如:
- 3 5
是不可能的时间表,因为游戏“ 5”的截止日期为1(这意味着它只能作为第一个游戏或不能作为全部游戏来玩)。如果您能意识到这一点,那么您将意识到以3 5
(3 5 0 ...
,3 5 1 ...
)开头的任何计划也是不可能的。
如果您以巧妙的顺序生成计划表,而跳过了您知道不可能的计划表,则可以利用这一事实。
算法提示
我建议以递归方式生成时间表。您在一个集合中拥有所有游戏ID(0、1等)。您从最低索引开始:0,从游戏集合中将其删除 ,并将其放入您的暂定时间表:
时间表:0
您检查它是否是有效的时间表(即,是否可以在该时间播放刚刚放在时间表中的游戏)。让我们假设是这种情况(在这种特定情况下,因为这是排程中的第一场比赛,应该总是可能的)。您还可以检查此暂定时间表是否比目前为止找到的分数更好。
然后,您尝试添加剩余游戏中剩余的最低游戏。在这种情况下,1
。您从游戏集中删除1
并将其放置在您的计划中也是同样的事情:
时间表:0 1
同样,您检查这是否是有效的计划。您已经知道可以先玩游戏0
,然后检查是否可以在第二位置玩游戏1
。不幸的是,游戏1
的时间限制使您无法这样做。不再需要探讨以0 1
开头的时间表。您已将1
从您的日程安排中删除,但没有在游戏收藏集中替换它:由于不可能在第二位置进行游戏,因此不值得进一步检查。相反,我将其放置在当前探索级别被“排除”的一系列游戏中。
然后您继续进行游戏集合中剩余的下一个游戏2
,并遵循相同的例程。如果您能够按时间表安排与时限兼容的游戏,则可以继续按时间表添加游戏中剩余的游戏。请注意,在某些情况下您可能完全填满了日程安排,但仍有游戏余地(反之亦然,您的日程安排仍然有漏洞,但尚无游戏可玩)。
当您用完所有选项后,就该从时间表中删除游戏了。删除您安排在时间表上的最后一个游戏,然后将其放回游戏集合中。还将您在当前级别上排除的游戏放回游戏收藏中。您可以继续计划的生成。不过请注意不要再次将您刚刚删除的游戏放在该级别。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。