如何在加权多数投票游戏中快速找到所有最小获胜联盟?

Posted

技术标签:

【中文标题】如何在加权多数投票游戏中快速找到所有最小获胜联盟?【英文标题】:How to find all minimal winning coalitions in a weighted-majority voting game in a fast way? 【发布时间】:2022-01-06 13:25:02 【问题描述】:

编辑:感谢论文A survey of algorithms for calculating power indices of weighted majority games,我找到了解决方案

我想解决以下问题:

给定一个集合 N=1,..,n,权重向量 W=w_1,..,w_n,按降序排序,总和为 1, 找到 N 的所有子集 C(也称为“联盟”),使得

    C 是“获胜”,即子集 C 内元素的权重之和超过某个阈值(例如 0.5) C 是“最小的”,这意味着从 C 中删除任何元素都将使子集不再“获胜”。

为了澄清,一个例子可以是:N=1,2,3 W=0.45,0.35,0.2

    这里的“获胜”子集是 1,2、2,3、1,3 和 1,2,3,因为它们的总权重都超过 0.5 只有 1,2、2,3 和 1,3 是最小的,因为在 1,2,3 中您可以删除一个元素并获取上面的元素。

从上面引用的论文中,我现在实现了这个代码,它递归地生成所有最小获胜联盟的列表

MWC = function(w,threshold=0.5)
  n = length(w)
  l = list()
  enumerate = function(S1,n1,b1)
    if(n1==n)
      return(list(c(S1,n1)))
    else
      if(sum(w[(n1+1):n]) >= b1)
        l = c(l,enumerate(S1,n1+1,b1))
      
      if(w[n1] >= b1)
        l=c(l,list(c(S1,n1)))
      else
        l = c(l,enumerate(c(S1,n1),n1+1,b1-w[n1]))
        return(l)
      
    
  
  return(enumerate(c(),1,threshold))


w = c(0.46,0.3,0.19,0.05)
MWC(w)

在指数复杂度使一切都不可行之后,代码运行到 n = 20 左右。

【问题讨论】:

为什么 2,3 在您的第一个样本中不是一个获胜的子集? 你说得对,我编辑了这个问题。对不起这个错误 【参考方案1】:

您的问题的一个解决方案是使用while loop 并在循环中应用上述约束。

下面是工作代码:

N = 1:10

W <- c(0.60, 0.40, 0.33, 0.30, 0.25, 0.20, 0.15, 0.10, 0.05, 0.03);

Winning_Sets <- c()

i <- 1

while (i != (length(N) - 1)) 
  if (i == 1) 
    Subsets <- combn(N, i)
   else 
    Keep_Combs <- Subsets[,which(Intermediate_Sets == 'No_Match')]
    Subsets <- combn(N, i)
    if (i == 2) 
      Subsets <- apply(Subsets, 2, function(x) 
        x <- x[x[i - 1] %in% Keep_Combs]
      )
     else 
      Subsets <- apply(Subsets, 2, function(x) 
        unlist(apply(Keep_Combs, 2, function(y) 
          if (identical(y, x[1:(i - 1)]) == TRUE) 
            x
            
          ))
        )
    
    Subsets <- do.call('cbind', Subsets)
  
  Intermediate_Sets <- apply(Subsets, 2, function(x) 
    if (sum(W[x]) > 0.5) 
      paste('', paste(x, collapse = ','), '', sep = '')
     else 
      'No_Match'
    
    )
  Winning_Sets <- append(Winning_Sets, unlist(Intermediate_Sets[Intermediate_Sets != 'No_Match']))
  if (length(which(Intermediate_Sets == 'No_Match')) > 0) 
    i <- i + 1
   else 
    i <- length(N) - 1
  

输出:

Winning_Sets
 [1] "1"          "2,3"        "2,4"        "2,5"        "2,6"        "2,7"       
 [7] "3,4"        "3,5"        "3,6"        "4,5"        "2,8,9"      "2,8,10"    
[13] "3,7,8"      "3,7,9"      "3,7,10"     "4,6,7"      "4,6,8"      "4,6,9"     
[19] "4,6,10"     "4,7,8"      "5,6,7"      "5,6,8"      "3,8,9,10"   "4,7,9,10"  
[25] "5,6,9,10"   "5,7,8,9"    "5,7,8,10"   "6,7,8,9,10"

【讨论】:

嗨,这段代码似乎并不总是有效(例如它不适用于 N = 1:3 W 但我认为可以通过传递组合一个不包括已删除元素的不同 N 来修复它......我会试试的! 我错过了检查这些条件,但通过添加一些约束可以解决它。你也能说出 N 有多大吗? 理想情况下约为 50,但我不知道这是否可行,因为子集的可能数量为 ( 2^57 - 1) ...但是越大越好,我的代码在 20 左右严重减速,我希望至少能达到 30...

以上是关于如何在加权多数投票游戏中快速找到所有最小获胜联盟?的主要内容,如果未能解决你的问题,请参考以下文章

英雄联盟怎么设置adc走A键

如何在 Weka 中尝试使用多数投票

ACM训练联盟周赛 C题 Alice和Bob的Nim游戏

对井字游戏获胜者的二维数组进行排序

联盟搜索算法

MinMax 树 - 当 Min 可以分两步获胜时