如何为两支球队的比赛找到最佳解决方案?

Posted

技术标签:

【中文标题】如何为两支球队的比赛找到最佳解决方案?【英文标题】:How to find an optimal solutions for 2 teams playing against each other? 【发布时间】:2021-12-27 16:36:36 【问题描述】:

给了我一张 A 队和 B 队的表格,其中每对 2 名球员都有一个号码。行代表A队球员,列代表B队球员。如果为正数,则表示A队比B队球员好,反之则为负数。

例如:

-710 415 527 -641 175 48
-447 -799 253 626 304 895
509 -523 -758 -678 -689 92
24 -318 -61 -9 174 255
487 408 696 861 -394 -67

两个团队都知道这张桌子。 现在,做的是A队报告5名球员,B队可以查看他们并为他们选择最好的5名球员。 如果我们想对球队进行比赛,我们知道每支球队都有一名队长被计算两次(就像一支球队有 6 名球员并且队长在那里两次),如果总和是正面,A队更好。

输入是数字a(行数/玩家A)和b(列/玩家B),表格如下:

6
6
-54 -927 428 -510 911 93
-710 415 527 -641 175 48
-447 -799 253 626 304 895
509 -523 -758 -678 -689 92
24 -318 -61 -9 174 255
487 408 696 861 -394 -67

输出应该是 1282。

所以,我所做的是将数字放入这样的矩阵中:

a, b = int(input()), int(input())

matrix = [list(map(int,input().split())) for _ in range(a)]

为此,我使用了 MinHeap 和 MaxHeap。我将行放入 MaxHeap 是因为 A 队想要最大的,然后我从中得到 5 个最好的 A 球员,如下所示:

for player, values in enumerate(matrix):
    maxheap.enqueue(sum(values), player)

playersA = []
overallA = 0

for i in range(5):
    ov, pl  = maxheap.remove_max()
    if i == 0: # it is a captain
        playersA.append(pl)
        overallA += ov
        
    playersA.append(pl)
    overallA += ov

B 团队知道 A 玩家使用 MinHeap 找到最好的 5 个玩家:

for i in range(b):
    player = []
    ov = 0
    for j in range(a): #take out a column of a matrix
        player.append(matrix[j][i])


    for rival in playersA: #counting only players already chosen by A
        ov += player[rival]

    minheap.enqueue(ov,i)

playersB = []
overallB = 0

for i in range(5):
    ov, pl = minheap.remove_min()
    if i == 0:
        playersB.append(pl)
        overallB += ov
        
    playersB.append(pl)
    overallB += ov

有球员,然后我从矩阵中计算总和:

out = 0
for a in playersA:
    for b in playersB:
        out += matrix[a][b]
print(out)

但是,此解决方案并不总是提供正确的解决方案。例如,它用于输入:

10
10
-802 -781 826 997 -403 243 -533 -694 195 182
103 182 -14 130 953 -900 43 334 -724 716
-350 506 184 691 -785 742 -303 -682 186 -520
25 -815 475 -407 -78 509 -512 714 898 243
758 -743 -504 -160 855 -792 -177 747 188 -190
333 -439 529 795 -500 112 625 -2 -994 282
824 498 -899 158 453 644 117 598 432 310
-799 594 933 -15 47 -687 68 480 -933 -631
741 400 979 -52 -78 -744 -573 -170 882 -610
-376 -928 -324 658 -538 811 -724 848 344 -308

但它不适合

11
11
279 475 -894 -641 -716 687 253 -451 580 -727 -509
880 -778 -867 -527 816 -458 -136 -517 217 58 740
360 -841 492 -3 940 754 -584 715 -389 438 -887
-739 664 972 838 -974 -802 799 258 628 3 815
952 -404 -273 -323 -948 674 687 233 62 -339 352
285 -535 -812 -452 -335 -452 -799 -902 691 195 -837
-78 56 459 -178 631 -348 481 608 -131 -575 732
-212 -826 -547 440 -399 -994 486 -382 -509 483 -786
-94 -983 785 -8 445 -462 -138 804 749 890 -890
-184 872 -341 776 447 -573 405 462 -76 -69 906
-617 704 292 287 464 -711 354 428 444 -42 45

所以问题是:可以这样完成还是有另一种快速算法( O(n ** 2 ) / O(n ** 3) 等),或者我只是尝试了所有可能的组合在 O(n!) 时间复杂度中使用蛮力?

【问题讨论】:

每支球队是否总是准确地选择 4 名球员 + 1 名队长,还是取决于每支球队的球员总数? 任何球员都可以被指定为队长吗? @AnneAunyme 是的,他们总是选择 5 个玩家 - 4 + 1。 @itprorh66 是的,可以。 您知道您的算法为何没有产生最佳结果吗?或者您想要对此进行解释吗? 【参考方案1】:

有一种方法可以通过多项式复杂度来做到这一点。

为了说明为什么您的解决方案不起作用,让我们考虑另一个更简单的问题。假设每支球队只选择2名球员,没有队长。

我们也取一个简单的分数矩阵:

1 1 1 2 1 1 1 1 1 1 0 3 0 2 0 0 0 0 0 4 0 0 0 0 4

在这里您可以看到 A 队没有获胜的机会(因为没有负数),但他们仍然会尽力而为。他们应该选谁?

使用您的算法,A 队应该选择他们最好的球员,他们的排名将是:

pa0

如果他们选择 pa3 和 pa4,他们的得分都是 4(这很糟糕,但没有 pa0 的 6 分那么差),B 队将赢 8 分(他们将选择 pb4 和另一个没有得分的玩家)没关系)。

另一方面,如果 A 队选择了 pa0 和 pa1(根据你的指标,它们比 pa3 和 pa4 差),那么最好的 B 队可以赢得 5 分(如果他们选择 pb3 和任何其他玩家)

基本上,您的近似没有考虑到 B 队只能选择两名球员,因此无法利用 pa0+pa1 的弱点,而它可以轻松利用 pa3+pa4 的弱点。

更好的解决方案是让 A 队仅通过考虑他们的 2 个最差分数(如果要选择 5 个玩家,则为 5 个)来评估每个玩家的分数:这将使排名如下:

pa2

这仍然是一个近似值:像 pa2+pa3 这样的一些组合实际上并不像听起来那么糟糕,再一次,弱点已经传播到 B 团队无法全部利用它们(尽管对于这个例子来说近似产生最好的结果)。

我们真正需要选择的不是两个最好的球员,而是两个球员的最佳组合,遗憾的是除了尝试所有的 $s!/(k!(sk)!) $ s 中 k 个玩家的组合(团队规模)。不过,还不错,因为 k=2 只是 $s*(s-1)/2$ 而 k=5 是 $s*(s-1)(s-2) em>(s-3)*(s-4)/5!$,尽管在 O(s^5) 中,但复杂度仍然是多项式。将队长添加到组合中只会将组合的数量乘以 k。它还需要改变如何计算分数,但你应该能够找到。

既然 A 队已经选择了他们的球员,那么 B 队就可以轻松地选择他们的球员了。这更简单,因为这里每个玩家都可以单独选择。


最后一个算法如何与开头提供的分数矩阵一起工作的示例。

A队有10种可能的组合:pa0+pa1、pa0+pa2、pa0+pa3、pa0+pa4、pa1+pa2、pa1+pa3、pa1+pa4、pa2+pa3、pa2+pa4、pa3+pa4。他们各自的分数是:5、8、7、7、7、6、6、7、7、8。

最好的组合是pa0+pa1,所以这就是他们发送给B队的东西。

B 队计算每个球员对 pa0+pa1 的得分:pb0:2, pb1:2, pb2:2, pb3:3, pb4:2。 pb3是最好的,其他都是平等的,因此B队发送pb3+pb4(例如),“答案”是5。

【讨论】:

那么,我是否只能通过尝试组合来做到这一点?因为最后 2 次输入耗时超过 10 秒,并且没有通过测试仪的时间限制。 你必须尝试 A 队的所有组合,而不是每支队伍中球员的总组合。作为 O(s^5) 复杂度,它不能很好地扩展,但如果你想显着加快速度,你将不得不接受有时你的程序不能提供最佳解决方案。 好的,所以对于每个组合和队长,我使用了一个优先队列从 B 队中选出 5 个最好的,它奏效了 :) 非常感谢!

以上是关于如何为两支球队的比赛找到最佳解决方案?的主要内容,如果未能解决你的问题,请参考以下文章

bzoj 3139: [Hnoi2013]比赛

bzoj3139: [Hnoi2013]比赛

我如何在 Core Data 中为球队、比赛和主客场球队关系建模?

如何为足球比赛设置球员预制件

练习二十二:python兵乓求比赛顺序练习,关于连个兵乓球队进行比赛

[BZOJ3139][HNOI2013]比赛(搜索)