算法:找到列表的最大元素

时间:2010-06-26 04:19:59

标签: algorithm

捕获:只允许列表元素之间的比较。例如,假设我们有1,000,000名国际象棋选手,我们被赋予了寻找该组中最佳国际象棋选手的任务。我们可以对任何其他国际象棋选手玩一个国际象棋选手现在,我们希望最小化任何玩家所玩游戏的最大数量

如果玩家 A 击败玩家 B B 击败 C ,我们可以假设 优于 C 。最小的 n 是什么,没有玩家玩 n 游戏?

@Carl:这不是作业;它实际上是SPOJ中一个更大问题的子问题。

4 个答案:

答案 0 :(得分:9)

我猜赌答案是人数的二进制日志。

您将二叉树设置为锦标赛阶梯。这意味着任何人玩的游戏都是树的高度。二叉树的高度为log n

答案 1 :(得分:1)

据我所知,没有任何算法可以解决您的问题而无需任何额外的外部信息来对玩家进行排名(例如播种)。如果你可以适当地播种球员,你可以找到最好的球员,而不是J. Wong建议的最差球员。

2轮10名球员的结果示例:A是最好的,ceil(log 10)= 4

A> B; C> d; E> F; G> H;我> Ĵ

A> C; B> Ë; F> G; D>我

答案 2 :(得分:1)

  

如何找到列表中最大的元素

如果列表是有序的,那么最大的元素是列表的第一个(或最后一个)元素。

如果没有订购清单,那么:

Element biggest = list.get(0);
for (Element e : list) {
    if (e.compareWith(biggest) > 0) {
        biggest = e;
    }
}

  

例如,假设我们有1,000,000名国际象棋选手,我们的任务是找到该组中最好的国际象棋选手。现在,我们希望尽量减少任何玩家玩游戏的最大数量。

使用最后一句的新约束......

答案#1:零游戏。比较国际象棋选手的排名和排名最高的排名是客观上最好的选手...根据排名。

答案#2:每位玩家最多玩ceiling(log2(nos_players))次游戏。 “淘汰”/淘汰锦标赛每轮淘汰了一半的球员,因此任意一名球员的轮次次数和最大游戏次数为ceiling(log2(nos_players))

相应的算法很简单:

List players = ...
while (players.size() > 1) {
    List winners = new ArrayList();
    Iterator it = players.iterator();
    while (it.hasNext()) {
        Player p1 = it.next();
        if (it.hasNext()) {
            Player p2 = it.next();
            int result = p1.compareTo(p2);
            if (result < 0) {
                winners.add(p2);
            } else if (result > 0) {
                winners.add(p1);
            } else {
                throw new Exception("draws are impossible in chess");
            }
        } else {
            winners.add(p1); // bye
        }
    }
    players = winners;
}

(除此之外:如果您还有一个预定的玩家排名和玩家数量N至少比ceiling(log2(N))少2,您可以安排最好的2名玩家获得再见如果最好的2名玩家在决赛中相遇,那么每个人将玩不到ceiling(log2(N))次游戏...这是对随机分配的byes的解决方案的改进。 )

实际上,答案#2不适用于国际象棋游戏,因为它没有考虑到很大比例的真正的国际象棋游戏是抽奖的事实;即两名球员都没赢。事实上,玩家A在一场比赛中击败玩家B的事实并不意味着A是比B更好的玩家。要确定谁是两个玩家中哪个更好,他们需要玩多个游戏和计算得失。简而言之,国际象棋选手存在“优于”关系的观点完全不切实际。


如果没有上述观点,淘汰赛并不是组织国际象棋锦标赛的实用方法。每个人都会在锦标赛组织者的桌子上露营,抱怨他们要比对自己更好(或更糟)的球员比赛。

真正的国际象棋(或类似)锦标赛的运作方式是您决定首先要玩的轮数。然后在“循环赛”锦标赛中,您按排名选择前N名球员。并安排每个玩家互相扮演玩家。获胜/抽奖得分最高的玩家是胜利者,如果出现平局,你可以使用(比方说)“对手得分总和”作为平局。还有其他风格的锦标赛,可以满足更多玩家/更少轮次。

答案 3 :(得分:1)

您可以用不同的方式重新解释您的目标,而不是构建抽象数据结构(如二叉树和解析锦标赛):

消除列表中最大

的所有元素

你会发现这样做可能比构建树和播种“锦标赛”在算法上更方便。

我可以证明,消除列表中不是最大的所有元素都可以通过每个元素log n调用/比较的最坏情况来完成。

如果可能,请处理原始列表的副本。

  1. 配对连续元素,并从列表中删除两者中较低的值。忽略未配对的元素,如果有的话。

    这可以通过从0&lt; = i&lt; int(n / 2)并比较索引2i2i+1

    即,对于n = 7,int(n / 2)= 3,i = 0,1,2;比较指数0和1,2和3,4和5.

  2. 应该删除总共int(n / 2)个指数。从n减去那个数。然后,重复1直到只剩下一个索引。这将是你最大的。

  3. 这是Ruby中的一个实现:

    def find_largest(list)
    
      n = list.size
      working_list = list.clone()
    
      while n > 1
    
        temp_list = Array.new()
    
        for i in (0...n/2)          # remember to cast n/2 to integer if not automatic
          if working_list[2*i] > working_list[2*i+1]
            new_list.push(working_list[2*i])
          else
            new_list.push(working_list[2*i+1])
          end
        end
    
        working_list = temp_list
    
        n -= n/2                    # remember to cast n/2 to integer if not automatic
    
      end
    
      return working_list[0]
    
    end