为什么我的搜索算法不能用于Project Euler 31?

时间:2017-04-02 00:58:32

标签: java algorithm search data-structures tree

问题31

  

在英格兰,货币由英镑,英镑和便士,p和   一般流通有八个硬币:1p,2p,5p,10p,20p,   50便士,1英镑(100便士)和2英镑(200便士)。有可能赚2英镑   以下方式:1×£1 + 1×50p + 2×20p + 1×5p + 1×2p + 3×1p多少   不同的方式可以使用任意数量的硬币2英镑?

static int[] nums = {200,100,50,20,10,5,2,1};
static int size = nums.length;
static HashMap<Integer,Integer> pivots = new HashMap<>();

public static int checkSum(HashMap<Integer,Integer> pivots){

    int target = 200;
    int sum = 0;

    for(Integer key: pivots.keySet()){
        int pivot = pivots.get(key);
        sum +=  nums[pivot];
        if(sum > target) return 1;
    }

    if(sum < target) return -1;

    return 0;
}

public static void shift(HashMap<Integer,Integer> pivots, int pivot_node){

    if(pivots.size() + nums[pivots.get(1)] == 201 && pivots.get(1) != 0){

        int p_1_value = pivots.get(1);   //this part checks whether the  current node(which is the first node)                                                                  
                                  //has reached children of all 1. 
                             //Which means it's time to shift the root node.
        pivots.clear();
        pivots.put(1 , p_1_value);
        shift(pivots, 1);
        return;
    }

    if(pivots.get(pivot_node) != size - 1) {
        pivots.put(pivot_node, pivots.get(pivot_node) + 1);
    }
    else{
        shift(pivots , pivot_node - 1);
    }

}



public static void branch(HashMap<Integer,Integer> pivots){
    pivots.put(pivots.size() + 1, pivots.get(pivots.size()));
}

public static int search(){
    int bool = checkSum(pivots);

    int n = 0;
    int count = 0;

    while(n < 25) {
        count++;
        if (bool == 0) {
            n++;     // if the sum is equal to 200, we shift the last 
                     //pivot to the next lower number.               
            shift(pivots, pivots.size());

        }else if (bool == -1) {   
            branch(pivots); //if the sum is less than 200, we make a new pivot with value of the last pivot.
        }else if (bool == 1) {    
            shift(pivots, pivots.size());  //if the sum is greater than 200,
                                          //we shift to the last pivot to the next lower number. 
        }
        bool = checkSum(pivots);
    }
    return n;
}

public static void main(String[] args){

    pivots.put(1,0);

    int n = search();

    System.out.print("\n\n------------\n\n"+ "n: " + n);

}

这是一种搜索与目标相加的集合的组合的算法。这有点像深度优先树搜索而不使用树。每个数据透视表示“树”上的节点。 shift()方法将节点的值更改为下一个较低的值。 branch()方法创建一个与最后一个节点具有相同值的新节点。 checkSum()方法检查枢轴的总和是否为&lt;,=或&gt;目标,200。

方法数量的正确答案应该是73000左右。但我的算法只返回约300种方式。 我不知道为什么会发生这种情况,因为我的算法应该达到每个可能的组合,等于200。

这是我的算法如何工作的可视化:

img

1 个答案:

答案 0 :(得分:2)

您的搜索算法找不到组成2英镑的所有可能的硬币组合,因为您只是将“最后一个支点”移动到下一个较低的数字,当您应该在最后一个之前考虑这些项目时。< / p>

您的算法会找到此组合:
100,50,20,20,5,2,2,1
但不是这个:
100,20,20,20,10,5,2,2,1

第二个组合中没有值50,但是你的算法将硬币值向后分解为仅向前--i.e.它将永远不会分解50,直到所有以下“枢轴”为1.您可以很容易地看到,如果您每次计数器n递增时打印HashMap<Integer,Integer> pivots

您可以尝试修改代码,方法是将代码修改为shift(),不仅使用最后一个支点,还使用所有不同的先前支点。但是,这样做会产生大量重复,因此您需要保留一份不同的已找到组合的列表。

解决问题31的另一种方法是使用动态编程。当涉及可以在较小位中分解的问题时,动态编程是最佳的。例如解决相同问题但在哪里 target = 2可用于解决target = 5的问题,target = 10可用于解决SELECT等问题。

祝你好运!