【问题标题】:State object overwrites previous child when producing a new one状态对象在生成新的子对象时覆盖前一个子对象
【发布时间】:2014-11-08 19:30:34
【问题描述】:

我在框架中使用回溯来解决边界修剪的图形着色问题。 图的每种可能状态(即可以放在图上的每种颜色组合)都由一个 State 对象表示。该框架要求每个州产生它所有的孩子,选择具有最佳界限的一个,并重复寻找最佳解决方案,并在此过程中进行边界修剪。我遇到的麻烦是:

当我在状态上调用 nextChild() 时,它会将由该状态产生的前一个孩子更改为与刚刚产生的孩子相同。

这是我认为与我的代码相关的部分:

    public State nextChild() {
//      System.out.println("currentColor: "+ colors.get(currentColor) + " firstUncolored " + this.firstUncolored);
//      previous line for debugging
        GraphColoringState child = childSetup();
        child.gcolors[firstUncolored] = colors.get(currentColor++);
        if(this.currentColor == colors.size()){
            this.currentColor = 0;
            this.hasMoreChildren = false;
        }
        return child;
    }

private GraphColoringState childSetup() {
        GraphColoringState theClone = new GraphColoringState(graph, colors);
        theClone.gcolors = this.gcolors;
        theClone.firstUncolored = this.firstUncolored +1;
        theClone.currentColor = 0;
        return theClone;
    }

当我制作和打印这样的孩子时:

State s = new GraphColoringState(graph, colors);
System.out.println(s);

State s1 = s.nextChild();
System.out.println(s1);

State s2 = s.nextChild();
System.out.println(s2);

State s3 = s.nextChild();
System.out.println(s3);     

我得到这个输出:

    , , , , , , 
Red, , , , , , 
Green, , , , , , 
Blue, , , , , , 

但是当我以这种方式制作和打印时:

System.out.println(s);

State s1 = s.nextChild();
State s2 = s.nextChild();
State s3 = s.nextChild();

System.out.println(s1);
System.out.println(s2);
System.out.println(s3); 

我得到了这个不幸的输出:

, , , , , , 
Blue, , , , , , 
Blue, , , , , , 
Blue, , , , , , 

我说这个输出很不幸,因为为了让回溯框架工作,我需要同时存储所有这些具有不同值的子节点。我曾尝试在每个州中使用数组实例变量来存储其子项,但无济于事。

为什么我的代码会改变我已经产生的孩子的值?

请,谢谢! :)

【问题讨论】:

    标签: java state backtracking


    【解决方案1】:

    gcolors 是您设置为新子元素的值的数组

    theClone.gcolors = this.gcolors;
    

    然后你在 nextChild() 中修改 gcolors

    child.gcolors[firstUncolored] = colors.get(currentColor++);
    

    为避免此类错误,您可以改用不可修改的列表。

    【讨论】:

    • 我不确定我是否理解 - 我应该将 gcolors 变量设为最终变量吗?由于我的代码试图按原样修改它,那不会抛出异常吗?
    • 如果你想保留年龄较大的孩子,那么你不能覆盖他们的状态。您可以通过将所有变量设为最终变量并将 gcolors 数组替换为列表来使 GraphColoringState 不可变。通过调用 Collections.unmodifiableList(..) 将列表包装到不可修改的列表中,确保列表也是不可变的。这样就不可能不小心改变了前一个孩子的状态。但是,最初的错误似乎是您将 gcolors 数组重用于副本,然后对其进行修改。
    • 我明白了。好吧,我找到了解决方案 - 我只是更改了 theClone.gcolors = this.gcolors;阅读 theClone.gcolors = this.gcolors.clone();真的很简单,我可能不需要打扰你们。感谢您的建议,祝您有美好的一天!
    【解决方案2】:

    原来问题出在这一行:

     theClone.gcolors = this.gcolors;
    

    这导致所有状态共享一个表示每个节点颜色的数组。我真正想要的是每个州都有自己的数组。

    将该行更改为:

    theClone.gcolors = this.gcolors.clone();
    

    这就是我们所需要的。谢谢大家的帮助!

    【讨论】:

      猜你喜欢
      • 2014-02-13
      • 2021-09-14
      • 2018-01-20
      • 2021-10-06
      • 2016-05-08
      • 1970-01-01
      • 2017-01-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多