E81086713E446D36F62B2AA2A3502B5EB155

Java杂家

杂七杂八。。。一家之言

BlogJava 首页 新随笔 联系 聚合 管理
  141 Posts :: 1 Stories :: 174 Comments :: 0 Trackbacks
六。 最小支撑树MST
给定一个简单有向图,要求权值最小的生成树,即求最小支撑树问题。
所谓生成树,就是说树的顶点集合等于给定图的顶点集合,且边集合包含于图的边集合。
也就说找出构成树的,经过所有顶点的,且权值最小的边集。
树的定义是要求无回路的,然后是要求连通的。

有两个比较经典的算法是:
1)Prim算法: 该算法的思想跟Dijstra算法非常相似,Dijstra算法中每次求出下一个顶点时依据的是离初始顶点最近的,而Prim算法则找离V1整个集合最近的,也就是从V1中某个节点出发到该顶点的边的权值最小。
其原理也是每次找局部最优,最后构成全局最优。
实现如下

@Override
    
public Edge[] prim() {
        MinHeap
<Edge> heap=new MinHeap<Edge>(Edge.class,numEdges);
        Edge[] edges
=new Edge[numVertexes-1];
        
//we start from 0
        int num=0;//record already how many edges;
        int startV=0;
        Arrays.fill(visitTags, 
false);
        Edge e;
        
for(e=firstEdge(startV);isEdge(e);e=nextEdge(e))
        {
            heap.insert(e);
        }
        visitTags[startV]
=true;
        
        
while(num<numVertexes-1&&!heap.isEmpty())//tree's edge number was n-1
        {
            
            e
=heap.removeMin();
        
            startV
=toVertex(e);
            
if(visitTags[startV])
            {
                
continue;
            }
            visitTags[startV]
=true;
            edges[num
++]=e;
            
for(e=firstEdge(startV);isEdge(e);e=nextEdge(e))
            {
                
if(!visitTags[toVertex(e)])//can't add already visit vertex, this may cause cycle
                heap.insert(e);
            }
            
                
            
        }
        
if(num<numVertexes-1)
        {
            
throw new IllegalArgumentException("not connected graph");
        }
        
return edges;
    }

/**
     * A Graph example
     * we mark the vertexes  with 0,1,2,.14 from left to right , up to down
     * S-8-B-4-A-2-C-7-D
     * |   |   |   |   |
     * 3   3   1   2   5
     * |   |   |   |   |
     * E-2-F-6-G-7-H-2-I
     * |   |   |   |   |
     * 6   1   1   1   2
     * |   |   |   |   |
     * J-5-K-1-L-3-M-3-T
     * 
     
*/
    
public static void testPrimMST() {
    

        
        DefaultGraph g
=new DefaultGraph(15);
        g.setEdge(
018);
        g.setEdge(
108);//its a undirected graph
        g.setEdge(124);
        g.setEdge(
214);
        g.setEdge(
232);
        g.setEdge(
322);
        g.setEdge(
347);
        g.setEdge(
437);
        
        g.setEdge(
053);
        g.setEdge(
503);
        g.setEdge(
163);
        g.setEdge(
613);
        g.setEdge(
271);
        g.setEdge(
721);
        g.setEdge(
382);
        g.setEdge(
832);
        g.setEdge(
495);
        g.setEdge(
945);
        
        
        g.setEdge(
562);
        g.setEdge(
652);
        g.setEdge(
676);
        g.setEdge(
766);
        g.setEdge(
787);
        g.setEdge(
877);
        g.setEdge(
892);
        g.setEdge(
982);
        
        
        g.setEdge(
1056);
        g.setEdge(
5106);
        g.setEdge(
1161);
        g.setEdge(
6111);
        g.setEdge(
1271);
        g.setEdge(
7121);
        g.setEdge(
1381);
        g.setEdge(
8131);
        g.setEdge(
1492);
        g.setEdge(
9142);
        
        g.setEdge(
10115);
        g.setEdge(
11105);
        g.setEdge(
11121);
        g.setEdge(
12111);
        g.setEdge(
12133);
        g.setEdge(
13123);
        g.setEdge(
13143);
        g.setEdge(
14133);
        
        g.assignLabels(
new String[]{"S","B","A","C","D","E","F","G","H","I","J","K","L","M","T"});
        Edge[] edges
=g.prim();
        
int total=0;
        
for(int i=0;i<edges.length;i++)
        {
            System.out.println(edges[i].toString(g));
            total
+=edges[i].getWeight();
        }
        System.out.println(
"MST total cost:"+total);
}

2)Kruskal算法:
该算法开始把,每个节点看成一个独立的两两不同的等价类,每次去权值最小的边,如果关联这条边的两个顶点在同一个等价类里那么这条边不能放入MST(最小生成树)中,否则放入MST中,并把这两个等价类合并成一个等价类。
继续从剩余边集里选最小的边,直到最后剩余一个等价类了。
该算法涉及等价类的合并/查找,一般用父指针树来实现。下面先给出父指针树实现的并查算法。
带路径压缩的算法,其查找时间代价可以看做是常数的。

package algorithms;

/**
 * 
@author yovn
 *
 
*/
public class ParentTree {
    
    
    
private static class PTreeNode
    {
        
int parentIndex=-1;
        
int numChildren=0;//only make sense in root

        
void setParent(int i) {
            
            parentIndex
=i;
            
        }
    }
    PTreeNode[] nodes;
    
int numPartions;
    
public ParentTree(int numNodes)
    {
        nodes
=new PTreeNode[numNodes];
        numPartions
=numNodes;
        
for(int i=0;i<numNodes;i++)
        {
            nodes[i]
=new PTreeNode();
            nodes[i].parentIndex
=-1;//means root
            
        }
        
    }
    
    
/**
     * use path compress
     * 
@param i
     * 
@return
     
*/
    
public int find(int i)
    {
        
if(nodes[i].parentIndex==-1)
        {
            
return i;
        }
        
else
        {
            nodes[i].setParent(find(nodes[i].parentIndex));
//compress the path
            return nodes[i].parentIndex;
        }
    }
    
    
public int numPartions()
    {
        
return numPartions;
    }
    
public boolean union(int i,int j)
    {
        
int pi=find(i);
        
int pj=find(j);
        
if(pi!=pj)
        {
            
if(nodes[pi].numChildren>nodes[pj].numChildren)
            {
                nodes[pj].setParent(pi);
                nodes[pj].numChildren
+=nodes[pi].numChildren;
                nodes[pi].numChildren
=0;
                
            }
            
else
            {
                nodes[pi].setParent(pj);
                nodes[pi].numChildren
+=nodes[pj].numChildren;
                nodes[pj].numChildren
=0;
            }
            numPartions
--;
            
return true;
        }
        
return false;
    }
    
}


从边集里权最小的边,我们又可以借助最小值堆来完成。有了父指针树以及最小值堆,现实Kruskal算法就很简单了:

@Override
    
public Edge[] kruskal() {
        Edge[] edges
=new Edge[numVertexes-1];
        ParentTree ptree
=new ParentTree(numVertexes);
        MinHeap
<Edge> heap=new MinHeap<Edge>(Edge.class,numEdges);
        
for(int i=0;i<numVertexes;i++)
        {
            
for(Edge e=firstEdge(i);isEdge(e);e=nextEdge(e))
            {
                heap.insert(e);
            }
        }
        
int index=0;
        
while(ptree.numPartions()>1)
        {
            Edge e
=heap.removeMin();
            
if(ptree.union(fromVertex(e),toVertex(e)))
            {
                edges[index
++]=e;
            }
        }
        
if(index<numVertexes-1)
        {
            
throw new IllegalArgumentException("Not a connected graph");
        }
        
return edges;
        
    }
OK,到此,图论的大概的算法算是复习完了。

posted on 2007-12-14 23:48 DoubleH 阅读(3671) 评论(1)  编辑  收藏 所属分类: Memorandum

Feedback

# re: 图及其算法复习(Java实现) 三:最小支撑树(Prim,Kruskal算法) 2010-10-27 23:16 斯蒂芬
toString没有定义。
不好使  回复  更多评论
  


只有注册用户登录后才能发表评论。


网站导航: