Тестирование схемы при реализации алгоритма Крускалса - PullRequest
8 голосов
/ 27 февраля 2012

Я пытаюсь написать программу, которая найдет минимальное связующее дерево.Но одна проблема, с которой я сталкиваюсь в этом алгоритме - это тестирование схемыЧто было бы лучшим способом сделать это в Java.

Хорошо, вот мой код

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

public class JungleRoads 
{
    public static int FindMinimumCost(ArrayList graph,int size)
    {
        int total = 0;
        int [] marked = new int[size];      //keeps track over integer in the mst

        //convert an arraylist to an array
        List<String> wrapper = graph;
        String[] arrayGraph = wrapper.toArray(new String[wrapper.size()]);
        String[] temp = new String[size];
        HashMap visited = new HashMap();


        for(int i = 0; i < size; i++)
        {
           // System.out.println(arrayGraph[i]);
            temp = arrayGraph[i].split(" ");

            //loop over connections of a current node
            for(int j =  2; j < Integer.parseInt(temp[1])*2+2; j++)
            {

                if(temp[j].matches("[0-9]+"))
                {
                    System.out.println(temp[j]);
                }
            }


        }


        graph.clear();
        return total;


    }


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

         FileReader fin = new FileReader("jungle.in");
        BufferedReader infile = new BufferedReader(fin);

        FileWriter fout = new FileWriter("jungle.out");
        BufferedWriter outfile = new BufferedWriter(fout);


        String line;
        line = infile.readLine();
        ArrayList graph = new ArrayList();

        do
        {

            int num = Integer.parseInt(line);
            if(num!= 0)
            {

                int size = Integer.parseInt(line)-1;

                for(int i=0; i < size; i++)
                {
                    line = infile.readLine(); 
                    graph.add(line);
                }

               outfile.write(FindMinimumCost(graph, size));
            }   


            line = infile.readLine();
        }while(!line.equals("0"));

    }
}

Ответы [ 5 ]

5 голосов
/ 01 апреля 2012

Алгоритм Крускалла не будет искать циклы, потому что он неэффективен;Но пытается создать компоненты дерева, а затем соединить их друг с другом.Как вы знаете, если вы соедините два разных дерева одним новым ребром, вы создадите новое дерево, и вам не нужно будет проверять циклы.

Если вы посмотрите на вики-страницу алгоритм выглядит следующим образом:

1. create a forest F (a set of trees), where each vertex in the graph is a separate tree
2. create a set S containing all the edges in the graph
3. while S is nonempty and F is not yet spanning
    a. remove an edge with minimum weight from S
    b. if that edge connects two different trees, then add it to the forest, combining 
       two trees into a single tree
    c. otherwise discard that edge.

Для этого следует использовать Несвязанная структура данных набора .снова из вики:

сначала отсортируйте ребра по весу, используя сортировку сравнения по времени O (E log E);это позволяет этапу «удалить ребро с минимальным весом из S» работать в постоянном времени.Далее мы используем структуру данных с несвязным множеством (Union & Find), чтобы отслеживать, какие вершины и в каких компонентах.Нам нужно выполнить операции O (E), две операции поиска и, возможно, одно объединение для каждого ребра.Даже простая структура данных с несвязным множеством, такая как леса с несвязным множеством с объединением по рангу, может выполнять операции O (E) за время O (E log V).Таким образом, общее время O (E log E) = O (E log V).


Создание непересекающихся лесов

Теперь вы можете взглянуть на Boost Graph Library - Инкрементные компоненты часть.Вы должны реализовать несколько методов: MakeSet , Find , Union , после этого вы можете реализовать алгоритм Kruskall.Все, что вы делаете, это работаете с некоторыми наборами, и самый простой способ сделать это - использовать связанный список.

Каждый набор имеет один элемент с именем репрезентативный элемент , который является первым элементом в наборе.

1- Сначала внедрите MakeSet по связанным спискам:

Это подготавливает структуру данных несвязанных наборов для алгоритма инкрементных связанных компонентов путем создания каждой вершины вотобразить член своего собственного компонента (или набора).

Вы должны просто инициализировать каждую вершину (элемент) как репрезентативный элемент нового набора, вы можете сделать это, установив их в качестве родителя:

 function MakeSet(x)
   x.parent := x

2- Реализация Найти метод:

Найти репрезентативный элемент множества, который содержит вершину x:

 function Find(x)
 if x.parent == x
    return x
 else
    return Find(x.parent)

The if Часть проверяет, является ли элемент представительным элементом или нет.мы устанавливаем все репрезентативные элементы наборов в качестве их первого элемента, устанавливая их как своих родителей.

3- И, наконец, когда вы получили все предыдущие вещи, простая часть реализует Union метод:

function Union(x, y)
 xRoot := Find(x) // find representative element of first element(set)
 yRoot := Find(y) // find representative element of second element(set)
 xRoot.parent := yRoot // set representative element of first set 
                       // as same as representative element of second set

Теперь, как вы должны запустить Kruskall?

Сначала поместите все узлы в n непересекающихся множеств с помощью метода MakeSet .На каждом шаге после нахождения нужного ребра (не отмеченного и минимального) найдите связанные наборы его вершин конечной точки методом Find (их репрезентативные элементы), если они одинаковые, отбросьте это ребро, потому что это ребро вызываетцикл, но если они находятся в разных наборах, используйте метод Union для объединения этих наборов.Поскольку каждый набор является деревом, объединение их является деревом.

Вы можете оптимизировать это, выбрав лучшую структуру данных для непересекающихся наборов, но пока я думаю, что этого достаточно.Если вас интересуют более сложные структуры данных, вы можете реализовать базовый способ rank , вы найдете его в вики. Это легко, но я не упомянул об этом, чтобы избежать недоумения.

2 голосов
/ 01 апреля 2012

Для проверки цепей вы захотите использовать структуру данных для поиска объединения.Самый простой способ сделать это - просто с помощью связанных списков, но есть более эффективные реализации.Эта ссылка может помочь вам, если вы хотите реализовать ее самостоятельно.

http://en.wikipedia.org/wiki/Disjoint-set_data_structure

Или вот ссылка на реализацию Java:

http://www.koders.com/java/fid125D835ECD1C1C701008C456A93A7179FA06D196.aspx

По сути, структура данных объединения-поиска позволяет отслеживать непересекающиеся наборы элементов и поддерживает две операции:

1) Find, which takes an element as an argument and tells you which set it is in
2) Union, which takes 2 disjoint sets and merges them

Допустим, ваш массив ребер, которые будут формировать MST, равен S.Идея состоит в том, что вы можете создать набор C, используя Union-Find, который отслеживает, какие вершины графа соединены ребрами в S.Когда C содержит все вершины в графе, тогда вы закончите, и проверка того, создаст ли добавление ребра цикл, сводится к проверке, находятся ли две соединенные вершины в C (используя две операции Find).

Таким образом, если E является набором всех ребер на графике, ваша операция обновления может продолжаться так:

    Remove edge, e from E, with minimum weight (say that it connects vertices v1 and v2)
    Find(v1) and Find(v2)
    If v1 and v2 are both in C then continue
    Else, Union(C,{v1,v2}) and append e to S

И вы останавливаетесьОбновление один раз C содержит каждую вершину графа.

2 голосов
/ 27 февраля 2012

Если вершины помечены каким-либо образом, все, что вам нужно сделать, это проверить, были ли ранее посещены обе вершины выбранного ребра, что будет означать петлю.

Так что, если он реализован с целыми числами, вы можете использовать логический массив, чтобы отметить, какие вершины были выбраны.

boolean[] visited = new boolean[vertex-count-1];

Или, если вершины помечены как строки, вы можете добавить их, например, на карту и проверить, что они еще не были добавлены.

0 голосов
/ 08 апреля 2012

Самый мощный, если не самый распространенный способ обнаружения циклов - это алгоритм SCC (Strongly Connected Components) Тарьяна.В любом случае на этот вопрос уже был дан ответ:

Поиск всех циклов в ориентированном графе

0 голосов
/ 03 апреля 2012

Если вы проверите цикл, используя DFS, это будет очень неэффективно. Но вы можете использовать Disjoint Set . При подключении вам нужно только проверить, находятся ли ваши узлы в одном подключенном компоненте.

Также обратите внимание, что вы должны проверить, что ваш оригинал подключен, потому что алгоритм Kruskall найдет связующий лес, а не связующее дерево в этом случае.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...