微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

贪婪算法,以最大化得分

如何解决贪婪算法,以最大化得分

我正在尝试在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并跟踪previousDeadlinecurrentDeadline。如果我们认为currentDeadlinepreviousDeadline大,那就意味着我们不能接受在此之前的任何截止日期。可以通过检查我们之前创建的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]

的列表。

这里是pastebin with code

,

我将尝试给出一种通用方法,而无需编写任何代码。

我将把您正在寻找的结果称为“时间表”。正如您在问题中所解释的那样,您可以在日程表中放置的最大游戏数由输入数据的“截止日期”列中的最大值表示。我将其称为“时间限制”。

您要的是贪婪算法。这样的算法将生成并检查所有游戏时间表,以找到使您的得分最大化的游戏时间表。

基本方法

您可以采用的最基本方法是生成“时限”或更短长度的所有游戏排列。对于其中的每一个,您都需要检查:

  • 这确实是一个有效的时间表吗?(暂定时间表中的每个游戏在放置时都应付款吗?)
  • 该暂定时间表的总成绩是否大于迄今为止获得的最佳成绩?如果是这样,您可以“保留”该解决方案,然后继续尝试其他时间表

第一种方法的主要困难是正确生成所有可能的时间表。即:

  • 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 53 5 0 ...3 5 1 ...)开头的任何计划也是不可能的。

如果您以巧妙的顺序生成计划表,而跳过了您知道不可能的计划表,则可以利用这一事实。

算法提示

我建议以递归方式生成时间表。您在一个集合中拥有所有游戏ID(0、1等)。您从最低索引开始:0,从游戏集合中将其删除 ,并将其放入您的暂定时间表:

时间表:0

您检查它是否是有效的时间表(即,是否可以在该时间播放刚刚放在时间表中的游戏)。让我们假设是这种情况(在这种特定情况下,因为这是排程中的第一场比赛,应该总是可能的)。您还可以检查此暂定时间表是否比目前为止找到的分数更好。

然后,您尝试添加剩余游戏中剩余的最低游戏。在这种情况下,1。您从游戏集中删除1并将其放置在您的计划中也是同样的事情:

时间表:0 1

同样,您检查这是否是有效的计划。您已经知道可以先玩游戏0,然后检查是否可以在第二位置玩游戏1。不幸的是,游戏1的时间限制使您无法这样做。不再需要探讨以0 1开头的时间表。您已将1从您的日程安排中删除,但没有在游戏收藏集中替换它:由于不可能在第二位置进行游戏,因此不值得进一步检查。相反,我将其放置在当前探索级别被“排除”的一系列游戏中。

然后您继续进行游戏集合中剩余的下一个游戏2,并遵循相同的例程。如果您能够按时间表安排与时限兼容的游戏,则可以继续按时间表添加游戏中剩余的游戏。请注意,在某些情况下您可能完全填满了日程安排,但仍有游戏余地(反之亦然,您的日程安排仍然有漏洞,但尚无游戏可玩)。

当您用完所有选项后,就该从时间表中删除游戏了。删除您安排在时间表上的最后一个游戏,然后将其放回游戏集合中。还将您在当前级别上排除的游戏放回游戏收藏中。您可以继续计划的生成。不过请注意不要再次将您刚刚删除的游戏放在该级别。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。