Java 有人知道下面这个骰子问题的更好的解决方案吗?

Java 有人知道下面这个骰子问题的更好的解决方案吗?,java,Java,有许多骰子,输入数组包含骰子正面朝上的数字。骰子是六面的。计算骰子的最小旋转总数,使所有面相同。1只需旋转一圈,即可使2、3、4和5面朝上,但需要至少旋转两圈才能使其成为面6,因为6是1的另一侧。2的对边是5,3的对边是4 我已经想出了一个解决办法,但我相信应该有更好的办法 例如: A={1,1,6},答案=2。旋转6两次,得到1 A={1,2,3},答案=2。旋转1和2,使其成为3 A={1,6,2,3},答案=3。旋转1、6和3使其全部为2 import java.util.*; publ

有许多骰子,输入数组包含骰子正面朝上的数字。骰子是六面的。计算骰子的最小旋转总数,使所有面相同。1只需旋转一圈,即可使2、3、4和5面朝上,但需要至少旋转两圈才能使其成为面6,因为6是1的另一侧。2的对边是5,3的对边是4

我已经想出了一个解决办法,但我相信应该有更好的办法

例如:

  • A={1,1,6}
    ,答案=2。旋转6两次,得到1
  • A={1,2,3}
    ,答案=2。旋转1和2,使其成为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;
    }}
    
    import java.util.*;
    公共类问题{
    公共静态void main(字符串参数[]){
    int[]A={3,4,1,2,4,2,3,5,1,2,3,4,6,2,4,1,5,2};
    Map countMap=新的HashMap();
    整数旋转=0;
    整数骰子计数;
    int maxDiceNumber=A[0];
    整数对立面的最大数;
    int max=1;
    对于(int i=1;i max){
    最大值=骰子计数;
    maxDiceNumber=i;
    }
    }
    如果(最大==1){
    如果(countMap.get(1).equals(countMap.get(6))&&countMap.get(1)!=0&&countMap.get(2)!=0){
    maxDiceNumber=2;
    }else如果(countMap.get(2).equals(countMap.get(5))&&countMap.get(2)!=0&&countMap.get(3)!=0){
    maxDiceNumber=3;
    }else如果(countMap.get(3).等于(countMap.get(4))&&countMap.get(1)!=0){
    maxDiceNumber=1;
    }else如果(countMap.get(2)!=0){
    maxDiceNumber=2;
    }else如果(countMap.get(5)!=0){
    maxDiceNumber=5;
    }else如果(countMap.get(6)!=0){
    maxDiceNumber=6;
    }
    }
    System.out.println(“最大骰子数:“+maxDiceNumber”);
    maxDiceNumber的对立面=CreateAntivative(maxDiceNumber);
    System.out.println(“相反的骰子编号:+相反的MaxDiceNumber”);
    迭代器it2=countMap.entrySet().Iterator();
    while(it2.hasNext()){
    Map.Entry对=(Map.Entry)it2.next();
    System.out.println(pair.getKey()+“=”+pair.getValue());
    如果((int)(pair.getValue())>0&&(int)(pair.getKey())!=maxDiceNumber){
    if((int)(pair.getKey())==MaxDiceNumber的对立面){
    旋转=旋转+(2*(int)(pair.getValue());
    }否则{
    旋转=旋转+((int)(pair.getValue());
    }
    }
    it2.remove();//避免ConcurrentModificationException
    }
    System.out.println(“最小旋转次数:“+旋转”);
    }
    私有静态int-createAntivative(int-key){
    开关(钥匙){
    案例1:
    返回6;
    案例2:
    返回5;
    案例3:
    返回4;
    案例4:
    返回3;
    案例5:
    返回2;
    案例6:
    返回1;
    }
    返回0;
    }}
    

  • 我想了一会儿,试图想出一个比暴力更好的解决办法;也就是说,不需要考虑如何将所有骰子都放到6个潜在位置。我打赌有一些聪明的方法可以做到这一点,但我想不出来

    因此,我编写了自己版本的暴力解决方案,试图大大简化您的代码。第一个观察结果是,骰子的两边加起来总是7,因此给定一个骰子值,从7中减去该值总是可以找到相反的结果。不需要一堆if语句,也不需要查找,或者其他任何东西。一个简单的减法就可以完成。如果你想知道两个位置是否相反,只要看看它们加起来是否等于7

    <> P> >我只写代码做最直接的事情…考虑每个骰子的位置,计算翻转的数量,把所有骰子拿到那个位置,并跟踪我们的最小翻转位置。p> 更新:可以做的一个优化是在每个位置创建一次模具数量。然后,我们不必每次通过外部循环处理每个模具,而是处理每个模具位置的计数。我更新了之前发布的代码的第一个版本,以使用此优化。这意味着不管你的列表中有多少骰子,你都要考虑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));
        }
    }
    

    这与您的代码给出的答案相同。

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

    • 这面朝上的骰子需要0圈
    • 对于反面朝上的骰子(如3对4),需要2圈
    • 对于所有其他骰子,它需要1回合
    您可以使用此函数编写如下函数:

    int turnsForSide(int 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);
    
    int[]A={3,4,1,2,4,2,3,5,1,2,3,4,6,2,4,1,5,2};
    映射计数=getSideCounts(A);
    Map turns=newhashmap();
    对于(int i=1;i<7;i++){
    旋转。旋转(i,旋转(i,计数));
    }
    //您还可以在上面的循环中保留最小值,以避免再次迭代
    turns.entrySet().stream().min(Comparator.comparing(Map.Entry::getValue))
    .map(entry->String.format(“最小金额:%d,用于第%d条)、entry.getValue()、entry.getKey()))
    .ifPresent(System.out::println);
    
    这是相当有效的,因为您只需要迭代原始数组一次,然后映射的边是固定的迭代次数(6),所以如果我正确地记住了复杂性理论,那么总体上这应该是O(n)

    我确实有函数的代码,但因为它似乎是家庭作业,我认为如果您尝试先编写它会更有帮助。

    public class>{
    
    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};
            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);
        }
    }
    
    公共静态void main(字符串参数[]){ int[]A={3,4,1,2,4,2,3,5,1,2,3,4,6,2,4,1,5,2}; int
    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};
            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);
        }
    }