2017-08-29 71 views
3

我被一个朋友问了一个编程问题,关于如何确定所有可能的组合值可以被添加到一个所需的总和。我有一个解决方案,但它不够优雅(它基本上只是一系列for循环和if语句)。我相信dplyr有一个我无法想到的解决方案,因为我知道它有多有用,但我还没有很好的解决它。我将在下面发布问题和我的脚本。确定所有可能的组合的值,总和为所需的总数

问题: 有一个有六个环的目标,每个环都值不同的值。这些值是1,2,3,4,5或6.您可以使用多少种不同的戒指组合来得分为9分?

所以要考虑: 顺序并不重要 只要你想 您可以使用尽可能少或尽可能多的价值可以得到相同的值不止一次(所以9 1的是一个完全有效的选项)

我考虑过首先使用combinat包中的combn(),但combn()不会替换值。

然后我决定使用一系列嵌套for循环和if语句(我将它截断为只能使用最多6个值的地方,因为虽然我可能有空闲时间,但我不是一个受虐狂的人编写一个允许最多9个值的循环)。所以基本上,它通过6个for-loops值得可能的值。我包含数字0到可能值的列表中以表示没有尝试,因为我只需要2个值而不是6个(因此4 + 5 + 0 + 0 + 0 + 0是此循环中的有效输出,但不会能够做4 + 5,因为它总是会尝试添加更多的非零值)。

## Create a vector x with possible values 
x = c(1,2,3,4,5,6) 

## Add in value 0 because I need to be able to write this dumb loop that allows many terms to be used, but also allows smaller amounts of terms to be used 

x = c(x,0);x 

## Creating empty data.frame to input solutions to so that I can check for uniqueness of solution 
df = data.frame("a" = as.numeric(), 
      "b" = as.numeric(), 
      "c" = as.numeric(), 
      "d" = as.numeric(), 
      "e" = as.numeric(), 
      "f" = as.numeric()) 

for (a in x){ 
    for (b in x){ 
    for (c in x){ 
     for (d in x){ 
     for (e in x){ 
      for (f in x){ 
      m = sum(a,b,c,d,e,f) 
      if(m == 9) { 
       p = 0 
       n = c(a,b,c,d,e,f) 
       if (nrow(df) == 0){ 
       df[1,] = n 
       } 
       if (nrow(df) >= 1){ 
       for (i in (1:nrow(df))){ 
        if(setequal(n,df[i,]) == TRUE){ 
        p = p+1 
        }} 
       if(p == 0){ 
        df = rbind(df,n) 
       } 
       } 
      } 
      } 
     } 
     } 
    } 
    } 
} 

## Convert any 0 values to NA 
df[df==0] = NA 

## Check Solutions 
df 

我创建了一个空data.frame存储解决方案,然后在循环中,我创建了一个测试,看看在回路中的新的解决方案以前发现的值的组合匹配,如果是这样,它不会将()绑定到data.frame。

我相信有一个更好的方法来做到这一点,允许动态最大数量的值(所以在这种情况下可以软编码,以将每个解决方案中的最大值数量改为9,而不是我的硬编码6,或者如果我想要的总数是5而不是9,则将其降至5)。如果您有任何建议可以减少这种笨拙的循环填充,我们将不胜感激!

+0

相关:[查找所有组合总和到目标的数字](https:// stackoverflow .COM /问题/ 30858688 /发现,所有组合-的号码 - 那森对一个目标); [生成所有排列的N球在M箱](https://stackoverflow.com/questions/27064675/generating-all-permutations-of-n-balls-in-m-bins) – Henrik

+1

E.g. '库(分区)'; 'p < - 部分(9)'; 'p [,colSums(p> 6)== 0]'。 – Henrik

+1

[所有可能的组合总和到目标值](https://stackoverflow.com/questions/32617501/all-possible-combinations-of-a-set-that-sum-to-a-target-价值) – Henrik

回答

2

你也许可以试试这个:

library(modelr) 
    library(dplyr) 
    range = 1:6 
    df = data.frame("a" = range, 
       "b" = range, 
       "c" = range, 
       "d" = range, 
       "e" = range, 
       "f" = range) 
    data_grid(df,a,b,c,d,e,f) %>% 
     mutate(sum = a+b+c+d+e+f) %>% 
     filter(sum == 9) %>% nrow 

这是函数:

foo <- function(sum_needed, max_value){ 
    range <- 1:max_value 
    df = data.frame("a" = range, 
       "b" = range, 
       "c" = range, 
       "d" = range, 
       "e" = range, 
       "f" = range) 
    result <- data_grid(df,a,b,c,d,e,f) %>% 
    mutate(sum = a+b+c+d+e+f) %>% 
    filter(sum == sum_needed) %>% nrow 
    return(result) 
} 
foo(9,6) 
#[1] 56 
+1

感谢您!我喜欢dplyr的管道系统,它只是我真的没有花时间去真正习惯使用的东西。 值得注意的是你和d。b下面列出了不同的数字,我认为你的数字是错误的。我认为手头的问题是排列组合。这里识别1 + 1 + 1 + 1 + 1 + 4与4 + 1 + 1 + 1 + 1 + 1不同。我认为,如果管道在过滤器后结束,那么您只剩下一个包含所有可行解决方案的data.frame,然后您可以找到一种方法来检查独特的组合,而不是直接对非独特的组合。 –

2
x = 1:6 
mysum = 9 

#Repeat each element of x as long the sum of repetitions does not exceed mysum 
temp = rep(x, floor(mysum/x)) 

#Calculate total unique combinations of temp that sum up to mysum 
sum(sapply(1:max(floor(mysum/x)), 
      function(i) sum(rowSums(unique(t(combn(temp, i)))) == mysum))) 
#[1] 26 

以下应列出所有的组合

sapply(1:max(floor(mysum/x)), function(i){ 
    temp2 = unique(t(combn(temp, i))) 
    temp2[rowSums(temp2) == mysum,] 
    }) 
+0

这看起来不错!谢谢!我也会尝试一些其他的数字。原来的问题有价值(16,17,23,24,39,40)和所需的总数为100,我只选择了我所做的这些值,因为该具体数字集只有一个答案,所以它不是很有趣(16 + 16 + 17 + 17 + 17 + 17)。从外观上看,这个解决方案也适用于这组数字。 –

相关问题