Algorithm 有效地计算一组给定的;积木;排成一行

Algorithm 有效地计算一组给定的;积木;排成一行,algorithm,language-agnostic,permutation,Algorithm,Language Agnostic,Permutation,我正在开发一个应用程序,其中我有许多块应该放在一条线上。也就是说,有不同数量的块,每个块的长度不同,应放置在线路上。块之间需要至少有一个空元素 我想有效地得到所有可能的块排列 例如,我有一条长度为15的线,希望放置大小为1、6和1的块 顺序问题,即在我的示例中,1尺寸块始终应位于6尺寸块的左侧和右侧 可能的排列是 X.XXXXXX.X..... X..XXXXXX.X.... ... .....X.XXXXXX.X 如何以更高级别的语言(如Java)高效地生成所有可能的排列?一种方法是递归地处

我正在开发一个应用程序,其中我有许多块应该放在一条线上。也就是说,有不同数量的块,每个块的长度不同,应放置在线路上。块之间需要至少有一个空元素

我想有效地得到所有可能的块排列

例如,我有一条长度为15的线,希望放置大小为1、6和1的块

顺序问题,即在我的示例中,1尺寸块始终应位于6尺寸块的左侧和右侧

可能的排列是

X.XXXXXX.X.....
X..XXXXXX.X....
...
.....X.XXXXXX.X

如何以更高级别的语言(如Java)高效地生成所有可能的排列?

一种方法是递归地处理它:

  • 如果存储中间只有一个空间的所有块所需的最小总长度超过了可用空间,则无法放置块
  • 否则,如果没有要放置的块,则放置块的唯一方法是保留所有未填充的方块
  • 否则,有两种选择。首先,您可以将第一个块放置在行中的第一个位置,然后在第一次在行的开头留出一个额外的空格后,将剩余的块递归地放置在行中的剩余空间中。其次,可以将行中的第一个空格留空,然后递归地将相同的块集放置在行中的剩余空格中。尝试这两种选择并将结果结合在一起应该会给你你想要的答案
  • 将这种递归逻辑转换为实际的Java应该不会太困难。下面的代码是为可读性而设计的,可以稍微优化一下:

    public List<String> allBlockOrderings(int rowLength, List<Integer> blockSizes) {
        /* Case 1: Not enough space left. */
        if (spaceNeededFor(blockSizes) > rowLength)) return Collections.EMPTY_LIST;
    
        List<String> result = new ArrayList<String>();
    
        /* Case 2: Nothing to place. */
        if (blockSizes.isEmpty()) {
            result.add(stringOf('.', rowLength));
        } else {
            /* Case 3a: place the very first block at the beginning of the row. */
            List<String> placeFirst = allBlockOrderings(rowLength - blockSizes.get(0) - 1,
                                                        blockSizes.subList(1, blockSizes.length()));
            for (String rest: placeFirst) {
                 result.add(stringOf('X', blockSizes.get(0)) + rest);
            }
    
            /* Case 3b: leave the very first spot open. */
            List<String> skipFirst = allBlockOrderings(rowLength - 1, blockSizes);
            for (String rest: skipFirst) {
                 result.add('.' + rest);
            }
        }
        return result;
    }
    
    public列出所有blockordering(int行长度,列出块大小){
    /*案例1:没有足够的空间*/
    if(spaceneedfor(blocksize)>rowLength))返回Collections.EMPTY_列表;
    列表结果=新建ArrayList();
    /*案例2:没什么可放的*/
    if(blockSizes.isEmpty()){
    结果.添加(stringOf('.',rowLength));
    }否则{
    /*案例3a:将第一个块放在行的开头*/
    List placeFirst=allBlockOrderings(行长度-blockSizes.get(0)-1,
    blockSizes.subList(1,blockSizes.length());
    for(字符串剩余:placeFirst){
    结果.add(stringOf('X',blocksize.get(0))+rest);
    }
    /*案例3b:让第一个位置保持打开状态*/
    List skipFirst=所有区块排序(行长-1,区块大小);
    用于(字符串休息:skipFirst){
    结果.添加('.'+rest);
    }
    }
    返回结果;
    }
    
    您需要实现
    spaceneedFor
    方法,该方法返回可能包含给定块列表的最短行的长度,以及
    stringOf
    方法,该方法接收一个字符和一个数字,然后返回给定字符的多个副本的字符串


    希望这有帮助

    一种方法是递归地接近它:

  • 如果存储中间只有一个空间的所有块所需的最小总长度超过了可用空间,则无法放置块
  • 否则,如果没有要放置的块,则放置块的唯一方法是保留所有未填充的方块
  • 否则,有两种选择。首先,您可以将第一个块放置在行中的第一个位置,然后在第一次在行的开头留出一个额外的空格后,将剩余的块递归地放置在行中的剩余空间中。其次,可以将行中的第一个空格留空,然后递归地将相同的块集放置在行中的剩余空格中。尝试这两种选择并将结果结合在一起应该会给你你想要的答案
  • 将这种递归逻辑转换为实际的Java应该不会太困难。下面的代码是为可读性而设计的,可以稍微优化一下:

    public List<String> allBlockOrderings(int rowLength, List<Integer> blockSizes) {
        /* Case 1: Not enough space left. */
        if (spaceNeededFor(blockSizes) > rowLength)) return Collections.EMPTY_LIST;
    
        List<String> result = new ArrayList<String>();
    
        /* Case 2: Nothing to place. */
        if (blockSizes.isEmpty()) {
            result.add(stringOf('.', rowLength));
        } else {
            /* Case 3a: place the very first block at the beginning of the row. */
            List<String> placeFirst = allBlockOrderings(rowLength - blockSizes.get(0) - 1,
                                                        blockSizes.subList(1, blockSizes.length()));
            for (String rest: placeFirst) {
                 result.add(stringOf('X', blockSizes.get(0)) + rest);
            }
    
            /* Case 3b: leave the very first spot open. */
            List<String> skipFirst = allBlockOrderings(rowLength - 1, blockSizes);
            for (String rest: skipFirst) {
                 result.add('.' + rest);
            }
        }
        return result;
    }
    
    public列出所有blockordering(int行长度,列出块大小){
    /*案例1:没有足够的空间*/
    if(spaceneedfor(blocksize)>rowLength))返回Collections.EMPTY_列表;
    列表结果=新建ArrayList();
    /*案例2:没什么可放的*/
    if(blockSizes.isEmpty()){
    结果.添加(stringOf('.',rowLength));
    }否则{
    /*案例3a:将第一个块放在行的开头*/
    List placeFirst=allBlockOrderings(行长度-blockSizes.get(0)-1,
    blockSizes.subList(1,blockSizes.length());
    for(字符串剩余:placeFirst){
    结果.add(stringOf('X',blocksize.get(0))+rest);
    }
    /*案例3b:让第一个位置保持打开状态*/
    List skipFirst=所有区块排序(行长-1,区块大小);
    用于(字符串休息:skipFirst){
    结果.添加('.'+rest);
    }
    }
    返回结果;
    }
    
    您需要实现
    spaceneedFor
    方法,该方法返回可能包含给定块列表的最短行的长度,以及
    stringOf
    方法,该方法接收一个字符和一个数字,然后返回给定字符的多个副本的字符串


    希望这有帮助

    很难确定什么是“高效实现”,因为输出可能非常大,因此即使是快速实现也不够快

    我会使用动态规划和递归技术来完成这样的任务。递归函数应该有两个参数——未使用的数字列表和行的剩余长度。里面将是一个简单的循环。您应该存储您已经知道的结果。我相信你可以自己处理细节。编辑:我们的朋友已经为y做过了
    free_dots = length_of_line - fixed_len.
    
    pos_count = number_of_blocks + 1