2017-08-29 84 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)。從外觀上看,這個解決方案也適用於這組數字。 –