Поиск в ширину для взвешенного ориентированного графа

Мне нужна помощь в добавлении стоимости Edge для моего алгоритма BFS. Я понятия не имею, как добавить стоимость ребра для каждой вершины, добавляемой к пути. Я опубликую код для вашей справки. Дайте мне несколько предложений.

График.java

package algo;
import java.util.*;


public class Graph 
{
    private static Map<String, LinkedHashSet<HashMap<String, Double>>> map;
    private ArrayList<String> nodes = new ArrayList<String>();
    private static ArrayList<String> shortestPath = new ArrayList<String>();
    public Graph()
    {

    }

    public Graph(String[] nodes)
    {
        map = new HashMap<String,LinkedHashSet<HashMap<String, Double>>>();
        for(int i=0;i<nodes.length;++i)
            map.put(nodes[i], new LinkedHashSet<HashMap<String, Double>>());
    }

    public void addNeighbor(String node1,String node2, Double edgeCost)
    {
        LinkedHashSet<HashMap<String, Double>> adjacent = map.get(node1);
        HashMap<String, Double> innerMap = new HashMap<String, Double>();
        if(map.get(node1)==null)
        {
            adjacent = new LinkedHashSet<HashMap<String, Double>>();                       
            map.put(node1, adjacent);
        }
        innerMap.put(node2, edgeCost);
        adjacent.add(innerMap);
    }

    public boolean memberOf(String node) {
        return nodes.contains(node);
    }

    public LinkedList<HashMap<String, Double>> getNeighbours(String node) {
        LinkedHashSet<HashMap<String, Double>> adjacent = map.get(node);
        if(adjacent==null) {
            return new LinkedList<HashMap<String, Double>>();
        }
        return new LinkedList<HashMap<String, Double>>(adjacent);
    }

    protected void storeNodes(String source, String destination) 
    {
        if (!source.equals(destination)) 
        {
            if (!nodes.contains(destination)) 
            {
                nodes.add(destination);
            }
        }
        if (!nodes.contains(source)) {
            nodes.add(source);
        }
    }

    public void getKeyValuePairs()
    {
        Iterator<String> iterator = map.keySet().iterator();

        while (iterator.hasNext()) 
        {
           String key = iterator.next().toString();
           LinkedHashSet<HashMap<String, Double>> value = map.get(key); 
           System.out.println(key + " " + value);
        }
    }
}

Main.java

package algo;
import java.io.*;

public class Main {

    public static void main(String[] args) throws IOException
    {
        File file = new File("city.txt");
        FileReader fr = new FileReader(file);
        BufferedReader br = new BufferedReader(fr);
        String line = br.readLine();
        String [] tokens = line.split("\\s+");
        String [] nodes = new String[tokens.length];

        for (int i = 0; i < nodes.length; ++i) {
            nodes[i] = tokens[i];
         }
        Graph g = new Graph(nodes);
        String var_1 = tokens[0];
        String var_2 = tokens[1];
        Double var_3 = Double.parseDouble(tokens[2]);
        g.addNeighbor(var_1, var_2,var_3);
        while((line = br.readLine())!=null)
        {
            tokens = line.split("\\s+");
            nodes = new String[tokens.length];
            for (int i = 0; i < nodes.length; ++i) {
                nodes[i] = tokens[i];
            }

            //Graph g = new Graph(nodes);
            var_1 = tokens[0];
            var_2 = tokens[1];
            var_3 = Double.parseDouble(tokens[2]);
            g.addNeighbor(var_1, var_2,var_3);
            g.storeNodes(var_1, var_2);
        }
        g.getKeyValuePairs();
        br.close();
     }

}

город.txt

city1  city2  5.5
city1  city3  6 
city2  city1  16  
city2  city3  26
city2  city4  15.5
city2  city5  7
city3  city4  9
city3  city5  5
city4  city1  3.6
city4  city2  4
city5  city2  7.9
city5  city3  5

это моя часть bfs моего кода, которую я тестировал без добавления каких-либо краевых затрат

public static ArrayList<String> breadthFirstSearch(Graph graph, 
            String source,
            String destination) 
    {
        shortestPath.clear();

        // A list that stores the path.
        ArrayList<String> path = new ArrayList<String>();

        // If the source is the same as destination, I'm done.
        if (source.equals(destination) && graph.memberOf(source)) 
        {
            path.add(source);
            return path;
        }
         // A queue to store the visited nodes.
        ArrayDeque<String> queue = new ArrayDeque<String>();

        // A queue to store the visited nodes.
        ArrayDeque<String> visited = new ArrayDeque<String>();

        queue.offer(source);
        while (!queue.isEmpty()) {
            String vertex = queue.poll();
            visited.offer(vertex);

            ArrayList<String> neighboursList = (ArrayList<String>) graph.getNeighbours(vertex);
            int index = 0;
            int neighboursSize = neighboursList.size();
            while (index != neighboursSize) {
                String neighbour = neighboursList.get(index);

                path.add(neighbour);
                path.add(vertex);

                if (neighbour.equals(destination)) {
                    return processPath(source, destination, path);
                } else {
                    if (!visited.contains(neighbour)) {
                        queue.offer(neighbour);
                    }
                }
                index++;
            }
        }
        return null;
    }

    public static ArrayList<String> processPath(String src,
                                                String destination,
                                                ArrayList<String> path) 
    {

        // Finds out where the destination node directly comes from.
        int index = path.indexOf(destination);
        String source = path.get(index + 1);

        // Adds the destination node to the shortestPath.
        shortestPath.add(0, destination);

        if (source.equals(src)) {
        // The original source node is found.
        shortestPath.add(0, src);
        return shortestPath;
        } else {
        // We find where the source node of the destination node
        // comes from.
        // We then set the source node to be the destination node.
        return processPath(src, source, path);
        }
    }

мой вопрос заключается в том, как добавить граничную стоимость в код в части bfs и указать стоимость пути от источника к месту назначения при выполнении.


person Karthi13    schedule 13.09.2016    source источник
comment
Хотя здорово, что вы поделились своим кодом, не могли бы вы, пожалуйста, в чем именно заключается вопрос? Я предполагаю, что вам нужно запустить BFS на графе со взвешенными ребрами (или, может быть, взвешенными узлами?). Пожалуйста, объясни   -  person shapiro yaacov    schedule 13.09.2016
comment
Также см. это: stackoverflow.com/questions/30409493/   -  person shapiro yaacov    schedule 13.09.2016
comment
Да. Прямо сейчас я могу запустить BFS с заданным источником и местом назначения, не включая стоимость, поэтому он предоставляет мне путь. Точно так же я хочу, чтобы bfs также принимали Edgecost и предоставляли мне стоимость достижения пункта назначения из источника. Например, если путь city1-›city3-›city5, связанная стоимость должна быть 11   -  person Karthi13    schedule 13.09.2016
comment
Отвечает ли это на ваш вопрос? Использование BFS для взвешенных графиков   -  person ggorlen    schedule 22.03.2021


Ответы (1)


Чтобы вернуть путь и стоимость, вам нужно создать класс для хранения обоих значений:

class CostedPath {
    private final List<String> path = new ArrayList<>();
    private double cost = 0.0;

    public CostedPath(String start) {
        path.add(start);
    }

    public CostedPath addNode(String node, Graph graph) {
        this.cost += graph.getCost(path.get(0), node);
        path.add(0, node);
        return this;
    }
}

Ваш поиск должен вернуть CostedPath из processPath.

private CostedPath processPath(String start, String end, List<String> path, Graph graph) {
{
    String previous = path.get(path.indexOf(end) + 1);
    if (previous.equals(start))
        return new CostedPath(start);
    else
        return processPath(start, previous, path, graph).addNode(end, graph);
}

Ваш код будет намного более читабельным, если вы разделите свои классы больше.

class Vertex {
    private final String name;
    private final Set<Edge> edges;
}

class Edge {
    private final Vertex end;
    private final double cost;
}

class Graph {
    private final Set<Vertex> vertices;
}

class Path {
    private final Vertex start;
    private final List<Edge> edges;
}

После того как вы это сделаете, вы обнаружите, что гораздо более очевидно, где добавить логику, связанную с конкретным классом, и необходимые вам данные будут доступны, когда они вам понадобятся. Например, теперь легко преобразовать Path в общую стоимость:

public double getCost() {
    return edges.stream().mapToDouble(Edge::getCost).sum();
}

Это гораздо более чистый код, чем необходимость обхода исходного графа, чтобы найти стоимость ребра.

person sprinter    schedule 13.09.2016