【问题标题】:Permutations of int arrays that sum to 16总和为 16 的 int 数组的排列
【发布时间】:2014-05-30 16:22:16
【问题描述】:

我有一个方法会根据值返回一个双精度值。数组中的每个 int 将介于 1 到 6 之间,表示连续掷骰子。

数组可以是 16 个插槽,也可以小到 4 个,并且顺序很重要。我不知道如何在 java 中编写代码来查看总计至少为 16 的每个排列。在线查找没有任何帮助。

下面是我可怜的代码

public double findMax() {
    int[] dice = new int[gameBoard.length];
    for(int x : dice) x = 1;
    double max = playGame(dice);
    /* 
    int pos = 0;
    for(int i = 0; i < dice.length; i++) {
        double test = playGame(dice);
        if(test > max) test = max;
    */

    //This is where I need help, to use the int[] dice for all combinations
    //playGame(dice) yields a double
}

【问题讨论】:

  • 所以本质上你想要那个数组的所有组合,总共可以得到 16 个?
  • 顺序敏感是的,数组大小不固定,让我更困惑
  • 但是正如你所提到的,它是关于一个骰子的......如何排列超过 6 个元素?
  • 也许我可以更清楚。每个索引都是掷骰子,结果是存储在骰子中的 int。因此,为了达到 16,我将掷出最多 16 个骰子,每个索引的 int 为 1
  • 知道了..稍后会为您提供代码..

标签: java arrays algorithm loops max


【解决方案1】:

这很简单。初始化一个足够大的数组。递归地填充数组的元素,直到达到 16(存储数组)或过冲(丢弃)。每次将数组添加到结果列表时不要忘记制作数组的深层副本,否则您将继续覆盖相同的数组。在代码中:

void createPermutations(int[] prefix, int index, int sum, List<Integer[]> results) {
    if (sum == 16) {
        results.add(createNewIntegerArray(prefix, index));
    } else if (sum < 16) {
        for (int i = 1; i <= 6; i++) {
            prefix[index] = i;
            createPermutations(prefix, index+1, sum+i, results);            
        }
    }
}

Integer[] createNewIntegerArray(int[] array, int length) {
    Integer[] result = new Integer[length];
    for (int i = 0; i < length; i++) {
        result[i] = array[i];
    }
    return result;
}

你可以这样称呼它:

createPermutations(new int[16], 0, 0, new ArrayList<Integer[]>());

编辑:如果我误解了您的问题并且您不关心“超出”目标值 (16),您应该将 == 更改为 &gt;=

【讨论】:

    【解决方案2】:

    你可以递归解决:

    Input: list of size n
    
    Solve(n) = { Sum(n,16) } + Solve(n-1)
    
    with: Solve(4) = { Sum(4,16) }
    
    Sum(n,16) = { find n numbers that sum up to 16 }
    

    那么我们有:

    Min(n) = 4
    
    Max(n) = 16
    
    Di = Input-List[i]
    
    Di = 1 or 2 or 3 or 4 or 5 or 6
    
    Sum(n,16) = { D1, D2, .. Dn } where D1 + D2 + .. + Dn = 16
    

    要解决Sum(n,16),你可以试试这个算法(写成Java代码):

    PairList<ArrayList<Byte>,Integer> sum (int n, int sum, ArrayList<Byte> list)
    {
        if (list.size() == 1)
            return new Pair<ArrayList<Byte>,Integer>(list, (int)list.get(0));
    
        PairList<ArrayList<Byte>,Integer> result
                      = new Pair<ArrayList<Byte>,Integer> ();
    
        for (int i=0; i<n; i++)
        {
            ArrayList<Byte> t = new ArrayList<Byte>(list);
            t.remove(i);
            PairList<ArrayList<Byte>,Integer> r = sum(n-1, sum, t);
    
            for (ArrayList<Byte> l : r.getFirstList())
                if (r.getSecond(l)+list.get(i) <= sum)
                {
                    l.append(list.get(i));
                    r.set(l, r.getSecond(l)+list.get(i));
                    result.append(r);
                }
        }
    
        return result;
    }
    

    然后Solve(n,16) 使用Sum(n,16)

    Map<Byte, PairList<ArrayList<Byte>,Integer>>
                solve (int min_n, int max_n, int sum, ArrayList<Byte> list)
    {
        Map<Byte, PairList<ArrayList<Byte>,Integer>> solution = null;
        solution = new Map<Byte, Pair<ArrayList<Byte>,Integer>> ();
    
        for (int i = min_n, i <= max_n; i++)
            solution.put(i, sum(i,sum,list));
    
       for (int i = min_n, i <= max_n; i++)
       {
           for (int j = 0; j < solution.get(i).count(); j++)
           {
               // remove all pairs that didn't sum up to total sum
    
               if (solution.get(i).getSecond(j) != sum)
                   solution.get(i).removePair(j);
           }
       }
    
        return solution;
    }
    

    注意:以上代码为伪代码

    【讨论】:

      【解决方案3】:

      有不同的方法可以做到这一点,但递归对我来说似乎是最好的(比如寻路算法)。看起来这应该是 4 到 16 个骰子的排列,总共 16 个或更大(如果数组的长度为 16,则每个可能的组合都会产生 16 或更大的值,所以我不确定是什么检查该长度的排列的目的将产生)。

      我可以使用 ArrayLists 或使用 Strings 来实现解决方案。我不想在递归函数中使用常规数组,因为它们依赖于固定大小。不过请务必添加import java.util.ArrayList;

      无论如何,这是我使用 ArrayLists 的代码版本。 (注意,我还没有测试过这段代码)

      public ArrayList<ArrayList<int>> findPermutations( int size ) {
      
          // To allow the function to work with sizes less than 1
          if ( size < 1 )
              return new ArrayList<ArrayList<int>>();
      
          ArrayList<ArrayList<int>> permutations = new ArrayList<ArrayList<int>>();
      
          ArrayList<ArrayList<int>> l1 = findPermutations( new ArrayList<int>(), size, 1 );
          l1.addAll( findPermutations( new ArrayList<int>(), size, 2 ) );
          l1.addAll( findPermutations( new ArrayList<int>(), size, 3 ) );
          l1.addAll( findPermutations( new ArrayList<int>(), size, 4 ) );
          l1.addAll( findPermutations( new ArrayList<int>(), size, 5 ) );
          l1.addAll( findPermutations( new ArrayList<int>(), size, 6 ) );
      
      
          for( ArrayList<int> a : l1 ) {
              if ( computeSum( a ) >= 16 ) {
                  permutations.add( a );
              }
          }
      
          return permutations;
      
      }
      
      public ArrayList<ArrayList<int>> findPermutations( ArrayList<int> record, int size, int value ) {
      
      
          record.add( value );
      
          if ( record.size() >= size ) {
              ArrayList<ArrayList<int>> bc = new ArrayList<ArrayList<int>>();
              bc.add( record );
              return bc;
          }
      
          ArrayList<ArrayList<int>> permutations = findPermutations( record.clone(), size, 1 );
          permutations.addAll( findPermutations( record.clone(), size, 2 ) );
          permutations.addAll( findPermutations( record.clone(), size, 3 ) );
          permutations.addAll( findPermutations( record.clone(), size, 4 ) );
          permutations.addAll( findPermutations( record.clone(), size, 5 ) );
          permutations.addAll( findPermutations( record.clone(), size, 6 ) );
      
          // For variable size array checking
          if ( record.size() >= 4 ) {
              permutations.add( record );
          }
      
      
          return permutations;
      }
      
      
      public int computeSum( ArrayList<int> list ) {
      
          int total = 0;
          for( int x : list ) {
              total += x;
          }
      
          return total;
      
      }
      

      当您调用此函数findPermutations( int size ) 时,您传入大小(数组长度,本质上是游戏板长度),它将生成总共至少有 16 个的所有掷骰子组合(特定于订单)。由于这会返回一个ArrayList,如果你想把它变成一个double数组,你可以使用ArrayList类的toArray()函数。

      ArrayList<ArrayList<int>> permutations = findPermutations( 16 );
      ArrayList<int>[] a = ( ArrayList<int>[] ) permutations.toArray();
      

      这会给你一个 ArrayList 数组

      要将其转换为数组数组,可以使用循环。

      int[][] finalVersion = new int[permutations.size()][16];
      for( int i = 0; i < permutations.size(); i++ ) {
          finalVersion[i] = ( int[] ) a[i].toArray();
      }
      

      这应该有望将其转换回数组数组。

      同样,我还没有在代码中测试过这个,所以要小心错误。我现在将对此进行测试,并在以后添加另一种不使用 ArrayLists 的计算方法。

      编辑:我稍微更改了代码,以允许 4 和大小之间的所有排列(您可以传入 16)。

      【讨论】:

      • 注意:递归调用可以更改为 for 循环,以使代码更小并允许可变骰子大小(如十二面体,12 面骰子)。我只是这样做,因为我很懒。
      • @Grog_MalBlood 因为我没有足够的代表来评论你的问题,所以我会在这里问你。您希望该函数列出大小 4 到 16 之间的所有排列,还是仅列出该范围内的固定大小?我问是因为我现在列出的代码只添加了固定大小的排列,但可以很容易地用两行代码将其更改为可变大小。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-06-05
      • 2022-01-03
      • 2019-07-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多