USACO(JAVA):算法完整搜索

时间:2015-03-26 07:36:22

标签: java algorithm data-structures

以下是问题陈述的链接:http://train.usaco.org/usacoprob2?a=ZSMwtXwq7ro&S=combo Problem Statement

编辑1:问题是这样的: 有一个锁,锁有2个有效的3位数组合。由用户设置的另一个是由制造商设置的主密钥。此外,锁具有一定的误差容限,即即使表盘上的数字分别位于有效组合的最多2个位置,它也会打开。

例如,假设用户设置密钥为1,2,3,主密钥(制造商设置)为4,5,6。对于这2个密钥,1,3,5是有效密钥,因为每个数字之间的差异此键和用户设置键的(在相同位置)至少为2 。但是,1,5,6是无效的组合,因为该键和用户组键的数字之间的差异> 2,主密钥相同。

基本上我正在做的事情非常天真,我正在生成所有可能的锁定组合并检查每个组合的有效性。这是我的代码

import java.util.*;
public class combo {
    public static void main(String[] args){
        Scanner myScanner = new Scanner(System.in);
        int N = myScanner.nextInt();
        int[] keys = new int[3];
        int[] masterKeys = new int[3];
        for(int i = 0; i < 3; i++){
            keys[i] = myScanner.nextInt();
        }
        for(int i = 0; i < 3; i++){
            masterKeys[i] = myScanner.nextInt();
        }
        int cnt = 0;
        int[] combo = new int[3];
        for(int i = 1; i <= N; i++){
            combo[0] = i;
            for(int j = 1; j <= N; j++){
                combo[1] = j;
                for(int k = 1; k <=N; k++){
                    combo[2] = k;
                    if(validCombo(combo, keys, masterKeys)){
                        cnt += 1;
                    }
                }
            }
        }
        System.out.println(cnt);
    }
// bug here
/*
Valid
combo : 1, 3, 5
key :  1, 2, 3
master 4, 5, 6

Invalid
1 5 6
 */
    public static boolean validCombo(int[] combo, int[] keys, int[] masterKeys){
        boolean checkKeys = true;
        boolean checkMasterKeys = true;
        for(int i = 0; i < 3; i++){
            if(Math.abs((int)(combo[i]-keys[i])) > 2){
                checkKeys = false;
            }
            if(Math.abs((int)(combo[i]-masterKeys[i])) > 2){
                checkMasterKeys = false;
            }
        }
        return checkKeys | checkMasterKeys;
    }
}

因此,对于输入N = 50,键= 1,2,3和masterKeys = 5,6,7,我得到输出184但是正确的输出是249(给定测试用例的样本)。任何人都可以请给我一个关于我的逻辑错误的提示

2 个答案:

答案 0 :(得分:1)

你没有考虑到数字环绕的事实 - 即,当N = 50时,那么50与1,2相距1,远离2,等等。

当尝试调试这样的东西时,如果你打印出你的程序正在计算的解决方案,然后比较问题网站上列出的输出,如果他们给你这些细节,或者只是使用额外信息,以验证您自己的思维过程。

答案 1 :(得分:0)

而不是&#34;尝试&#34;您可以计算它们的所有组合

  1. 计算每个刻度盘的重叠数量

    如果键号与主键号之间的距离为
    is >= 5 --> you have 10 distinct values
    is < 5 --> you have (5 - distance) overlapping numbers
    例子:
    key: 3 master key: 8 distinct numbers: 10 = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
    key: 3 master key: 6 distinct numbers: 8 = 1, 2, 3, 4, 5, 6, 7, 8 4 and 5 are the overlapping numbers for this dial

  2. 如果至少有一个表盘没有重叠数字,那么我们最多有250个组合

  3. 如果所有刻度盘至少有一个重叠数字,我们可以计算
    通过乘以重叠数来重叠组合的数量
    所有表盘
  4. 唯一组合可以计算为max. number - overlapping combinations
  5. 示例:key:3,4,5主密钥:7,8,9

     1  2  3 -+
     2  3  4  |
     3  4  5  |<-- the combinations close to the key
     4  5  6  |
     5  6  7 -+<-- the only overlapping number
     6  7  8  |
     7  8  9  |<-- the combinations close to the master key
     9 10 11  |
    10 11 12 -+
    
    There are 249 valid combinations.
    

    这是一个简短的计算片段。

    int numbersPerDail = 50;
    int dials = 3;
    int[] keys = {2, 2, 3};
    int[] masterKeys = {48, 5, 6};
    
    int[] overlappingNumbers = new int[dials];
    for (int i = 0; i < dials; i++) {
        int distance = Math.max(keys[i], masterKeys[i]) - Math.min(keys[i], masterKeys[i]);
        if (distance >= 46) { // the dial is circular 
            distance = numbersPerDail - distance;
        }
        overlappingNumbers[i] = 5 - distance;
    }
    
    int doubleCombos = 0;
    if (overlappingNumbers[0] > 0 && overlappingNumbers[1] > 0 && overlappingNumbers[2] > 0) {
        doubleCombos = overlappingNumbers[0] * overlappingNumbers[1] * overlappingNumbers[2];
    }
    System.out.println("valid combinations = " + (250 - doubleCombos));