有谁知道更好的解决以下骰子问题的方法?

时间:2019-06-22 04:49:16

标签: java

有一个骰子,输入数组包含骰子正面朝上的数字。骰子面对6张。计算骰子的最小旋转总数,以使所有面相同。 1只需旋转一圈即可使2、3、4和5朝上,但至少需要旋转两次即可使其面6,因为6是1的反面。2的反面是5和3是4。

我已经提出了解决方案,但是我认为应该有一个更好的解决方案。

例如:

  1. A = {1,1,6},答案=2。旋转6次以得到1。
  2. A = {1,2,3},答案=2。旋转1和2并使其变为3。
  3. A = {1,6,2,3},答案=3。旋转1、6和3使其全部变为2。

    import java.util.*;
    
    public class DiceProblem {
        public static void main(String args[]){
        int[] A = {3,4,1,2,4,2,3,5,1,2,3,4,6,2,4,1,5,2};
        Map<Integer, Integer> countMap = new HashMap<>();
        int rotation = 0;
        int diceCount;
        int maxDiceNumber = A[0];
        int OppositeOfMaxDiceNumber;
        int max = 1;
    
        for(int i = 1; i <= 6 ; i++){
            diceCount = 0;
            for (int value : A) {
                if(i == value){
                    diceCount++;
                }
            }
            countMap.put(i, diceCount);
            if(diceCount > max){
                max = diceCount;
                maxDiceNumber = i;
            }
        }
    
        if(max == 1){
            if(countMap.get(1).equals(countMap.get(6)) && countMap.get(1) != 0 && countMap.get(2) != 0){
                maxDiceNumber = 2;
            }else if(countMap.get(2).equals(countMap.get(5))  && countMap.get(2) != 0 && countMap.get(3) != 0){
                maxDiceNumber = 3;
            }else if(countMap.get(3).equals(countMap.get(4)) && countMap.get(1) != 0){
                maxDiceNumber = 1;
            }else if(countMap.get(2) != 0){
                maxDiceNumber = 2;
            }else if(countMap.get(5) != 0){
                maxDiceNumber = 5;
            }else if(countMap.get(6) != 0){
                maxDiceNumber = 6;
            }
        }
    
        System.out.println("Max Dice Number: "+ maxDiceNumber);
        OppositeOfMaxDiceNumber = createOpposite(maxDiceNumber);
        System.out.println("Opposite Dice Number: "+ OppositeOfMaxDiceNumber);
    
        Iterator it2 = countMap.entrySet().iterator();
        while (it2.hasNext()) {
            Map.Entry pair = (Map.Entry)it2.next();
            System.out.println(pair.getKey() + " = " + pair.getValue());
            if((int)(pair.getValue()) > 0 && (int)(pair.getKey()) != maxDiceNumber){
                if((int)(pair.getKey()) == OppositeOfMaxDiceNumber){
                    rotation = rotation + (2  * (int)(pair.getValue()));
                }else {
                    rotation = rotation + ((int)(pair.getValue()));
                }
            }
    
            it2.remove(); // avoids a ConcurrentModificationException
        }
        System.out.println("Number of Minimum Rotations: "+ rotation);
    
    }
    private static int createOpposite(int key){
        switch (key) {
            case 1:
                return 6;
            case 2:
                return 5;
            case 3:
                return 4;
            case 4:
                return 3;
            case 5:
                return 2;
            case 6:
                return 1;
        }
        return 0;
    }}
    

3 个答案:

答案 0 :(得分:2)

我想了一段时间,试图提出一种比蛮力更好的解决方案;也就是说,不只是考虑将所有骰子都拿到6个潜在位置中的每个位置将需要什么。我敢打赌,有一些聪明的方法可以做到这一点,但我无法提出。

因此,我编写了自己的蛮力解决方案版本,以期简化您的代码。第一个观察结果是,骰子的两侧总是相加7,因此,如果给定骰子值,则总是通过从7中减去该值来找到相反的值。不需要一堆if语句,任何查找或任何其他操作。一个简单的减法就可以完成。而且,如果要查看两个位置是否相反,只需查看它们是否加起来为7。

然后,我刚刚编写代码来做最直接的事情...考虑每个骰子位置,计算翻转次数以使所有骰子都到达该位置,并跟踪前进的最小翻转位置。

更新:可以做的一种优化是在每个位置仅创建一次模具数量。然后,我们不必每次都通过外循环处理每个模具,而是处理每个模具的位置计数。我更新了之前发布的代码的第一个版本,以使用此优化。这意味着无论列表中有多少个骰子,您都将拥有6 * 6 = 36对位置。

有了这些,这是我想出的代码:

public class DiceProblem {

    public static void main(String args[]) {

        int[] A = {3,4,1,2,4,2,3,5,1,2,3,4,6,2,4,1,5,2};

        // Figure out how many dice we have in each position
        int[] pos_counts = {0, 0, 0, 0, 0, 0, 0};
        for (int start_pos : A)
            pos_counts[start_pos] += 1;

        // Initilize our accumulators for minimum flips and which position that was
        int min_flips = Integer.MAX_VALUE;
        int min_flip_pos = 0;

        // Consider each of the 6 dice positions...
        for (int position = 1 ; position <= 6 ; position++) {

            // initialize the number of flips
            int flips = 0;

            // Go through all the dice starting positions and tally up the flips necessary to get all dice to the position
            // we are considering
            for (int start_pos = 1 ;  start_pos <= 6 ; start_pos++) {
                if (start_pos + position == 7)  // opposite sides of a dice always add up to 7
                    flips += 2 * pos_counts[start_pos];
                else if (start_pos != position)
                    flips += pos_counts[start_pos];
            }

            // If this is a smaller number of flips than we've seen before, record it as the new best choice
            if (flips < min_flips) {
                min_flips = flips;
                min_flip_pos = position;
            }
        }

        System.out.println(String.format("%d flips to die position %d", min_flips, min_flip_pos));
    }
}

结果:

15 flips to die position 2

与您的代码得出的答案相同。

答案 1 :(得分:0)

要获得一个好的解决方案,请考虑每侧要转多少圈。

  • 对于骰子已经朝上的情况,它需要转0圈。
  • 如果骰子的另一侧朝上(例如3代表4),则需要2圈。
  • 对于所有其他骰子,需要转一圈。

您可以使用它来编写如下函数:

int turnsForSide(int side, Map<Integer, Long> sideCount);

side是您要寻找的一面; Map<Integer, Long> sideCount的键指示骰子的一面,以及该面具有的骰子数量的值。

现在您要做的就是获取每一侧的计数;那是微不足道的。编写这样的函数:

Map<Integer, Long> getSideCounts(int[] sidesUp);

如果您具有这两个功能,则可以迭代地图并找到最小值的一面。

int[] A = {3,4,1,2,4,2,3,5,1,2,3,4,6,2,4,1,5,2};
Map<Integer, Long> counts = getSideCounts(A);
Map<Integer,Integer> turns = new HashMap<Integer, Integer>();
for (int i = 1; i < 7; i++) {
    turns.put(i, turnsForSide(i, counts));
}
// you could also retain the minimum in the loop above to avoid another iteration
turns.entrySet().stream().min(Comparator.comparing(Map.Entry::getValue))
        .map(entry -> String.format("minimum amount: %d for side %d", entry.getValue(), entry.getKey()))
        .ifPresent(System.out::println);

这是相当有效的,因为您只需要迭代原始数组一次,然后迭代带有固定迭代次数(6)的边的映射,因此如果我正确地记住复杂性理论,则总体而言应该为O(n)

我确实具有这些功能的代码,但是由于这似乎是一项家庭作业,因此,如果您尝试先编写它,那会有所帮助。

答案 2 :(得分:0)

公共类DiceProblem {     公共静态void main(String args []){

    int[] A = {3,4,1,2,4,2,3,5,1,2,3,4,6,2,4,1,5,2};
    int flip_count;
    int min_flip_count = 9999999;

    for (int value : A) {
        flip_count = 0;
        for (int i : A) {
            if (value == i) {
                flip_count += 0;
            } else if (value + i == 7) {
                flip_count += 2;
            } else {
                flip_count += 1;
            }
        }
        if (flip_count < min_flip_count) {
            min_flip_count = flip_count;
        }
    }

    System.out.println("Minimum Flip Count:" + min_flip_count);
}

}