使用Ford Fulkerson算法找到优势?

时间:2012-01-06 18:30:48

标签: c++ algorithm graph-theory flow ford-fulkerson

我正在尝试用C ++实现Ford Fulkerson算法。

但是,我的find_edge功能出现问题。当我在my_alg中调用此函数时,它会选择正确的边,然后在my_alg中增加流量。它选择右边缘并增加其流量(flow),但是当我再次调用find_edge函数时,流量不会按原样递增。

这导致我的算法无限循环。可能我对指针做错了。你可以在下面看到我的代码。

//An object of this class represents an edge in the graph.
class Edge
{
private:
    //Node *prev;

public:
    int flow;

    Edge(Node *firstNode, Node *secNode, unsigned inCost) {
        orgNode = firstNode;
        dstNode = secNode;
        bridge_capacity = inCost;
    }

    Edge() {
        flow=0;
    }
};

//An object of this class holds a vertex of the graph
class Node
{
public:
    Node *prev;

    vector<Edge>& getAdjNodeList() {
        return adjNodeList;
    }
};

Edge *find_edge(Graph *g,Node *from,Node *to) {
    vector<Edge> b=from->getAdjNodeList();
    for(int i=0;i<b.size();i++) {
        if(b[i].getDstNode()==to)
            return (&b[i]);
    }
    return NULL;
}

int my_alg(Graph *as,Node *source,Node *sink){
    Edge *find_edge();

    int max_flow=0;

    while(bfs(as,source,sink)) {
        Node *b=as->nodeList[num_isl];
        int inc=100000000;
        while(b->prev!=NULL) {
            Edge *bok=find_edge(as,b->prev,b);
            inc=min(inc,bok->get_bridge_capacity()-bok->flow);
            b=b->prev;
        }

        b=as->nodeList[num_isl];

        while(b->prev!=NULL){
            Edge *bok = find_edge(as,b->prev,b);
            bok->flow += inc;       // This is the place the flow is incremented
            bout << bok->flow;      // Here, everything is alright.
            bok = find_edge(as,b->prev,b);
            cout << bok->flow;      // However, this is is not the correct result.
        }
        max_flow+=inc;
    }
    return max_flow;
}

1 个答案:

答案 0 :(得分:4)

我对您的代码有了更全面的了解。为了帮助您将来自己跟踪问题,我将向您展示一个查找错误的示例流程。

如果您通过查看代码确实无法找到问题,则可能需要删除所有混淆视图问题的内容。简化代码可能如下所示:

class Edge {
public:
    int flow;
};    

class Node {
private:
    vector<Edge> adjNodeList; // list of outgoing edges for this vertex

public:
    vector<Edge> & getAdjNodeList() {
        return adjNodeList;
    }

    void addAdjNode(Node* newAdj) {
        adjNodeList.push_back(Edge(newAdj));
    }
 };    


int main() {
    Node *node1 = new Node();
    Node *node2 = new Node();
    node1->addAdjNode(node2);

    vector<Edge> t = node1->getAdjNodeList();
    vector<Edge> f = node1->getAdjNodeList();
    t[0].flow = 11;

    cout << t[0] << endl;
    cout << f[0] << endl;
}

如果您要运行此代码,您会注意到t[0]f[0]不一样。由于我刚刚复制了代码的关键元素,原因应该仍然相同。

这里发生了什么?致电时

vector<Edge> t = node1->getAdjNodeList();

邻接列表是通过引用返回的,它应该为您提供原始列表的引用 - 您应该能够更改它的元素,不应该吗?但是,在将此引用分配给新分配的向量t时,将调用隐式复制构造函数,因此t将包含向量的副本(!),而您希望保存引用。

要解决此问题,您可以完成以下操作:

vector<Edge> & t = node1->getAdjNodeList();

保存引用并且不创建新对象。

我只能假设为什么指针在函数调用之间碰巧是相同的:每次都可能将对象复制到同一个地方。此外,请注意您增加了不再存在的对象的值 - 该副本已在find_edge - 调用结束时删除。

由于您没有自行跟踪问题,因此需要一些时间来回答您的问题。如果您已经给出了上述示例,我打赌您的解决方案将在几分钟内完成。我们鼓励您在堆栈溢出时提出问题 - 但是,大多数成员不愿意通过大量代码来自行识别问题。这意味着,高质量的答案通常需要直接提出问题。 (最后一段旨在帮助您将来,但是,可以在不改变问题的情况下减少它。)

除此之外,我强烈建议你不要像你那样使用你的物品。通过将所有内容作为引用传递并在对象外部进行所有更改,您基本上绕过了使面向对象编程变得强大的封装。例如,如果您刚刚向increaseFlow(Edge* to, int increment)添加了另一个函数Node并且已经完成了对象内的所有操作,那么它将更加明智(并且不会给您提供问题)。

希望我能提供帮助。