在实施Kruskal算法时测试电路

时间:2012-02-27 04:07:52

标签: java algorithm data-structures disjoint-sets

我正在尝试编写一个可以找到最小生成树的程序。但我对这个算法的一个问题是测试电路。在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 个答案:

答案 0 :(得分:5)

Kruskall的算法不会搜索周期,因为它不具有性能效率;但是尝试创建树的组件,然后将它们相互连接。如您所知,如果您使用一个新边连接两个不同的树,您将创建新树,而无需检查周期。

如果你看wiki page算法如下:

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.

您应该使用Disjoint Set Data Structure。再次来自维基:

  

首先使用O(E log E)中的比较排序按重量对边进行排序   时间;这允许步骤“从S移除最小重量的边缘”   在恒定的时间内运作。接下来,我们使用不相交的数据   结构(Union&amp; Find)来跟踪哪个顶点在哪个顶点   组件。我们需要执行O(E)操作,两个'find'操作   每个边缘可能有一个联合。甚至是简单的不相交数据集   通过等级联合的不相交森林等结构可以执行   O(E log V)时间内的O(E)操作。因此总时间为O(E log E)   = O(E log V)。


创建不相交的森林

现在你可以看看Boost Graph Library-Incremental Components部分。 您应该实现一些方法: MakeSet 查找联盟,之后您可以实施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)

if部分检查元素是否是代表元素。我们将集合的所有代表性元素设置为它们的第一个元素,方法是将它们设置为自己的父元素。

3-最后当你得到所有以前的东西时,简单的部分是实施联盟方法:

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?

首先通过 MakeSet 方法将所有节点放在n不相交的集合中。在找到所需边缘(未检查和最小值)之后的每个步骤中,通过查找方法(它们的代表元素)找到其端点顶点的相关集合,如果它们相同,则将此边缘删除,因为此边缘导致循环,但如果它们位于不同的集合中,请使用 Union 方法合并这些集合。因为每个集合都是树的结合。

您可以通过为不相交集选择更好的数据结构来优化这一点,但现在我认为已经足够了。如果您对更高级的数据结构感兴趣,可以实现排名基础方式,您可以在wiki中找到它,这很容易,但我没有提及它以防止困惑。

答案 1 :(得分:2)

如果顶点以某种方式标记,您需要做的就是检查所选边缘的两个顶点是否先前已被访问过,这将指示一个循环。

因此,如果使用整数实现,则可以使用布尔数组来标记已选择的顶点。

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

或者如果顶点标记为字符串,您可以将它们添加到Map中,并检查它们是否尚未添加。

答案 2 :(得分:2)

要检查电路,您需要使用union-find数据结构。最简单的方法是使用链表,但是有更高效的实现。如果您想自己实施,可以使用此链接。

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

或者这里是java实现的链接:

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

基本上,union-find数据结构允许您跟踪不相交的元素集,并支持两个操作:

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。我们的想法是,您可以使用Union-Find创建一个集C,它跟踪图表的哪些顶点通过S中的边连接。当C包含图表中的所有顶点时,您就完成了,并检查边缘的添加是否会创建一个周期,相当于检查它连接的两个顶点是否已经在{{1 (通过使用两个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 包含图表的每个顶点,就会停止更新。

答案 3 :(得分:0)

如果你检查周期,使用DFS将是非常低效的。但您可以使用Disjoint Set。连接时,您只需要检查节点是否在同一个连接组件中。

另请注意,您必须检查原件是否已连接,因为在这种情况下,Kruskall算法将找到生成林而不是生成树。

答案 4 :(得分:0)

检测周期的最强大但最常见的方法是通过Tarjan的SCC(强连接组件)算法。无论如何,这个问题已经得到了回答:

Finding all cycles in a directed graph