Java MaxFlow算法,生成边缘的麻烦

时间:2017-02-23 23:11:44

标签: java graph max-flow

我正在尝试使用具有无限权重边的图来解决最大流问题,但每个节点都有容量。我使用ford fulkerson算法解决了这个问题,并将每个节点分成一个in节点和一个out节点,其容量是两者之间的加权边缘。当我在边缘硬编码时(参见代码中注释掉的块),我的算法工作得很好,但是当我尝试从文本文件构建边时,总是返回零。对于我的生活,我无法弄清楚为什么,我已经检查确保所有边缘都正确构造,并且无法弄清楚什么是错误的。

读取图形的文本文件(第1行为边,第2行为节点容量) (1 2)(2 3)(2 5)(3 4)(4 5)(3 5) (2 1500)(3 1000)(4 800)

shops = shops.all()[of:of+per_page]

Edge Class

import java.util.*;
import java.io.*;

public class Main {


//Add Node to Graph
public static void make_node(Map<String, List<Edge>> graph, String node_v) {
    List<Edge> empty = new ArrayList<>();
    if(!graph.containsKey(node_v)) {
        graph.put(node_v, empty);
    }
}

//Create Edge
public static void make_edge(Map<String, List<Edge>> graph, Map<Edge, Integer> flow_graph, String node_u, String node_v, int weight) {
    Edge edge = new Edge(node_u, node_v, weight);
    Edge residual_flow = new Edge(node_v, node_u, 0);

    edge.setRisedge(residual_flow);
    residual_flow.setRisedge(edge);

    if (graph.containsKey(node_u)) {
        List<Edge> edge_list = graph.get(node_u);
        edge_list.add(edge);
        graph.put(node_u, edge_list);
    }
    if (graph.containsKey(node_v)) {
        List<Edge> edge_list = graph.get(node_v);
        edge_list.add(residual_flow);
        graph.put(node_v, edge_list);
    }

    flow_graph.put(edge, 0);
    flow_graph.put(residual_flow, 0);

}

//Find valid path to Sink
public static List<Edge> get_path(Map<String, List<Edge>> graph, Map<Edge, Integer> flow_graph, String source, String sink, List<Edge> path) {
    if (source == sink)
        return path;

    int residual;
    List<Edge> result;

    for (Edge edge : graph.get(source)) {
        residual = edge.getCapacity() - flow_graph.get(edge);
        if (residual > 0 && !path.contains(edge) && !path.contains(edge.getRisedge())) {
            path.add(edge);
            result = get_path(graph, flow_graph, edge.getSink(), sink, path);
            if (result != null) {
                return result;
            }

        }
    }
    return null;
}

//Find Max Flow
public static int find_max_flow(Map<String, List<Edge>> graph, Map<Edge, Integer> flow_graph, String source, String sink) {
    List<Edge> path = new ArrayList<>();
    path = get_path(graph, flow_graph, source, sink, path);
    List<Integer> residuals = new ArrayList<>();
    int min_path_flow;

    while (path != null) {
        for (Edge edge : path) {
            residuals.add(edge.getCapacity() - flow_graph.get(edge));
        }
        min_path_flow = Collections.min(residuals);

        for (Edge edge : path) {
            flow_graph.put(edge, flow_graph.get(edge) + min_path_flow);
            flow_graph.put(edge.getRisedge(), flow_graph.get(edge.getRisedge()) - min_path_flow);
        }
        List<Edge> empty = new ArrayList<>();
        path = get_path(graph, flow_graph, source, sink, empty);
    }

    int max_flow = 0;
    for (Edge edge : graph.get(source)) {
        max_flow += flow_graph.get(edge);
    }
    return max_flow;
}

public static void main(String[] args) throws IOException {

    Map<String, List<Edge>> graph = new HashMap<>();
    Map<Edge, Integer> flow_graph = new HashMap<>();
    Map<String, Integer> capacity_dict = new HashMap<>();
    List<String> in_out_nodes = new ArrayList<>();

    //Get file name
    Scanner scan = new Scanner(System.in);
    System.out.println("Enter file name:");
    String filename = scan.nextLine();
    File file = new File(filename);

    BufferedReader reader = new BufferedReader(new FileReader(file));

    String graph_text = reader.readLine();
    String capacity_text = reader.readLine();

    //Parse Capacity
    capacity_text = capacity_text.replace(")", "");
    capacity_text = capacity_text.replace("(", "");
    String[] split_capacity = capacity_text.split("\\s");

    //Parse Graph
    graph_text = graph_text.replace(")", "");
    graph_text = graph_text.replace("(", "");
    String[] split_graph = graph_text.split("\\s");

    //Parse Capacity
    for (int i = 0; i < split_capacity.length; i++){
        if(!capacity_dict.containsKey(split_capacity[i])){
            capacity_dict.put(split_capacity[i],Integer.valueOf(split_capacity[i+1]));
            in_out_nodes.add(split_capacity[i]);
            i = i+1;
        }
    }

    //Make nodes
    for (String s : split_graph){
        make_node(graph, s + "out");
        make_node(graph, s + "in");
    }

    //Make edges
    for (int i = 0; i < split_graph.length; i ++){
        String u = split_graph[i] + "out";
        String ui = split_graph[i] + "in";
        String v = split_graph[i + 1] + "in";

        if(in_out_nodes.contains(split_graph[i])){
            in_out_nodes.remove(split_graph[i]);
            make_edge(graph,flow_graph,u,ui, capacity_dict.get(split_graph[i]) );
        }

        if(capacity_dict.containsKey(split_graph[i])){
            make_edge(graph,flow_graph,u,v, capacity_dict.get(split_graph[i]) );

        }else{
            make_edge(graph,flow_graph,u,v, capacity_dict.get(split_graph[i + 1]) );

        }
        i += 1;
    }

    //Code works when i comment out my generated edges and use these
    //make_edge(graph,flow_graph, "1out","2in",1500);
    //make_edge(graph,flow_graph, "2out","3in",1500);
    //make_edge(graph,flow_graph, "2out","5in",1500);
    //make_edge(graph,flow_graph, "3out","4in",1000);
    //make_edge(graph,flow_graph, "4out","5in",800);
    //make_edge(graph,flow_graph, "3out","5in",1000);
    //make_edge(graph,flow_graph, "2in","2out",1500);
    //make_edge(graph,flow_graph, "3in","3out",1000);
    //make_edge(graph,flow_graph, "4in","4out",800);

    System.out.print(find_max_flow(graph, flow_graph, "1out", "5in"));
}
}

1 个答案:

答案 0 :(得分:0)

嗯,说实话,你的代码很乱。我不知道你的失败点是什么。由于您的程序适用于硬编码边缘,因此图形出现问题。事实上,我创建了一些输出来比较两个图形。

您的硬编码图如下所示。边缘由

表示

name_of_source -> name_of_sink (capacity)

1in: []
2in: [2in -> 1out (0), 2in -> 2out (0)]
3in: [3in -> 2out (0), 3in -> 3out (0)]
4in: [4in -> 3out (0), 4in -> 4out (0)]
5in: [5in -> 2out (0), 5in -> 4out (0), 5in -> 3out (0)]
1out: [1out -> 2in (1500)]
2out: [2out -> 2in (1500), 2out -> 3in (1500), 2out -> 5in (1500)]
3out: [3out -> 3in (1000), 3out -> 4in (1000), 3out -> 5in (1000)]
4out: [4out -> 4in (800), 4out -> 5in (800)]
5out: []

但是当你在没有硬编码的情况下构建相同的图形时,你会得到:

1in: []
2in: [2in -> 1out (0), 2in -> 2out (1500)]
3in: [3in -> 2out (0), 3in -> 3out (1000)]
4in: [4in -> 3out (0), 4in -> 4out (800)]
5in: [5in -> 2out (0), 5in -> 4out (0), 5in -> 3out (0)]
1out: [1out -> 2in (1500)]
2out: [2out -> 3in (1500), 2out -> 5in (1500), 2out -> 2in (0)]
3out: [3out -> 4in (1000), 3out -> 5in (1000), 3out -> 3in (0)]
4out: [4out -> 5in (800), 4out -> 4in (0)]
5out: []

要定义任何类的字符串表示形式,必须覆盖Object中的toString()方法。我在Edge类中添加了以下方法来生成此输出。

@Override
public String toString(){
    return source + " -> " + sink + " (" + capacity + ")";
}

以下代码生成图变量的输出:

for ( String k : graph.keySet() )
    System.out.println( k + ": " + graph.get(k));

我非常确定您有足够的帮助解决问题。