我正在尝试编写一个可以找到最小生成树的程序。但我对这个算法的一个问题是测试电路。在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"));
}
}
答案 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(强连接组件)算法。无论如何,这个问题已经得到了回答: