【问题标题】: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(也称为“联盟”),使得

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

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

  1. 这里的“获胜”子集是 {1,2}、{2,3}、{1,3} 和 {1,2,3},因为它们的总权重都超过 0.5
  2. 只有 {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} 在您的第一个样本中不是一个获胜的子集?
  • 你说得对,我编辑了这个问题。对不起这个错误

标签: r algorithm tree subset weighted


【解决方案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...
猜你喜欢
  • 2014-01-16
  • 1970-01-01
  • 2022-01-10
  • 2015-04-27
  • 1970-01-01
  • 1970-01-01
  • 2018-04-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多