【问题标题】:Permutation of N listsN个列表的排列
【发布时间】:2012-04-08 10:55:10
【问题描述】:

我需要 N 个列表中的所有排列,直到程序开始我才知道 N,这是我的 SSCCE(我已经实现了建议给我的算法,但它有一些错误)。

首先,创建 Place 类:

public class Place {
public List<Integer> tokens ;

//constructor
public Place() {

  this.tokens = new ArrayList<Integer>();  
}

}

然后测试类:

public class TestyParmutace {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        // TODO code application logic here

        List<Place> places = new ArrayList<Place>();

        Place place1 = new Place();
        place1.tokens.add(1);
        place1.tokens.add(2);
        place1.tokens.add(3);
        places.add(place1); //add place to the list

        Place place2 = new Place();
        place2.tokens.add(3);
        place2.tokens.add(4);
        place2.tokens.add(5);
        places.add(place2); //add place to the list

        Place place3 = new Place();
        place3.tokens.add(6);
        place3.tokens.add(7);
        place3.tokens.add(8);
        places.add(place3); //add place to the list


        //so we have
        //P1 = {1,2,3}
        //P2 = {3,4,5}
        //P3 = {6,7,8}


        List<Integer> tokens = new ArrayList<Integer>();

        Func(places,0,tokens);

    }

    /**
     * 
     * @param places list of places
     * @param index index of current place
     * @param tokens list of tokens
     * @return true if we passed guard, false if we did not
     */


    public static boolean Func( List<Place> places, int index, List<Integer> tokens) 

    {

        if (index >= places.size())
            {

                // if control reaches here, it means that we've recursed through a particular combination
                // ( consisting of exactly 1 token from each place ), and there are no more "places" left



                String outputTokens = "";
                for (int i = 0; i< tokens.size(); i++) {

                    outputTokens+= tokens.get(i) +",";
                }
                System.out.println("Tokens: "+outputTokens);

                if (tokens.get(0) == 4 && tokens.get(1) == 5 && tokens.get(2) == 10) {
                    System.out.println("we passed the guard with 3,5,8");
                    return true;
                }

                else {
                    tokens.remove(tokens.get(tokens.size()-1));
                    return false;
                }

            }

        Place p = places.get(index);

        for (int i = 0; i< p.tokens.size(); i++)
            {

                tokens.add(p.tokens.get(i));
                //System.out.println("Pridali sme token:" + p.tokens.get(i));

                if ( Func( places, index+1, tokens ) ) return true;

            }
        if (tokens.size()>0)
            tokens.remove(tokens.get(0));

        return false;

    }
}

这是这段代码的输出:

Tokens: 1,3,6,
Tokens: 1,3,7,
Tokens: 1,3,8,
Tokens: 3,4,6,
Tokens: 3,4,7,
Tokens: 3,4,8,
Tokens: 4,5,6,
Tokens: 4,5,7,
Tokens: 4,5,8,
Tokens: 2,3,6,
Tokens: 2,3,7,
Tokens: 2,3,8,
Tokens: 3,4,6,
Tokens: 3,4,7,
Tokens: 3,4,8,
Tokens: 4,5,6,
Tokens: 4,5,7,
Tokens: 4,5,8,
Tokens: 3,3,6,
Tokens: 3,3,7,
Tokens: 3,3,8,
Tokens: 3,4,6,
Tokens: 3,4,7,
Tokens: 3,4,8,
Tokens: 4,5,6,
Tokens: 4,5,7,
Tokens: 4,5,8,

所以,你看,有些组合是正确的 (1,3,6),有些是不正确的 (4,5,8),有些是完全缺失的 (2,4,8,..) 如何解决这个问题?地方的数量和地方的令牌数量可能会有所不同,我只使用了 3 个地方,因为有 2 个地方可以工作,但是更多的地方它是错误的。 谢谢。

【问题讨论】:

  • 为什么 (4,5,8) 不正确而 (2,4,8) 正确。每个都必须来自不同的列表??
  • 是的,就像你说的那样。每个令牌都必须来自不同的列表。
  • 这个任务来自更复杂的程序 - petri 网编辑器/模拟器,所有转换都可以有保护 - 如果这个转换要被执行,这个条件必须是真的......并且成功这个保护,我需要占用所有输入位置,并尝试其令牌的所有组合以通过此守卫。 place 有标记列表,输入位置的数量是可变的..这就是为什么我需要从 N 个列表中组合。
  • @PovedzHeslo 我认为您需要首先获得所有可能的排列。然后过滤它们并留下那些通过警戒的。用两种不同的方法来做。
  • 你可能是对的,谢谢你的建议。

标签: java list permutation


【解决方案1】:

你的算法几乎是正确的。我认为您不需要返回truefalse 并在获得true 时停止当前迭代。我修改了你的方法Func

public static void Func( List<Place> places, int index, Deque<Integer> tokens) {
    if (index == places.size()) {
        // if control reaches here, it means that we've recursed through a particular combination
        // ( consisting of exactly 1 token from each place ), and there are no more "places" left
        String outputTokens = "";
        for (int token : tokens) {
            outputTokens += token + ",";
        }
        System.out.println("Tokens: "+outputTokens);
    } else {
        Place p = places.get(index);
        for (int token : p.tokens) {
            tokens.addLast(token);
            Func(places, index+1, tokens);
            token.removeLast();
        }
    }
}

我使用了Deque,因为它提供了方便的removeLast 方法来删​​除最后添加的令牌。您可以将LinkedList 作为Deque 的实现传递。

更新

List<List<Integer>> combinations;

// Instead of printing result:
List<Integer> copy = new ArrayList<Integer>(tokens);
combinations.add(copy);

【讨论】:

  • 嗨,你知道如何保存令牌组合吗?我尝试使用整数双端队列列表,但是每当我将令牌组合添加到最终列表时,它仍然是空的,因为我打电话token.removeLast() 之后,看起来最终列表只包含参考。
【解决方案2】:

您正在尝试设置交叉产品,而不是真正的排列。所以你需要这样做

 for(Integer token1 : place1.tokens){
    for(Integer token2 : place2.tokens){
       for(Integer token3 : place3.tokens){
            //crossValue = (token1, token2, token3);
        }
    }
 }

现在,如果你想拥有所有排列,例如 [1,3,6,] 也有 [1,6,3][3,6,1] 等。你需要一个函数来输出给定列表或数组的排列,请参阅 Permutation of array

【讨论】:

  • 但是你忘记了地方的数量是N,而不是3。
  • 是的,我查看了这个问题,因为我有带有这些硬编码循环的遗留代码,需要更新为动态算法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-05-31
  • 1970-01-01
  • 2021-11-23
  • 2016-07-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多