E81086713E446D36F62B2AA2A3502B5EB155

          Java雜家

          雜七雜八。。。一家之言

          BlogJava 首頁 新隨筆 聯系 聚合 管理
            40 Posts :: 1 Stories :: 174 Comments :: 0 Trackbacks

          公告

          所有文章和代碼除非特別說明, 均為本blog作者原創,轉載請注明出處和原作者. 謝謝!

          常用鏈接

          留言簿(15)

          隨筆分類

          隨筆檔案

          相冊

          搜索

          積分與排名

          最新評論

          閱讀排行榜

          評論排行榜

          六。 最小支撐樹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 閱讀(3695) 評論(1)  編輯  收藏 所屬分類: Memorandum

          Feedback

          # re: 圖及其算法復習(Java實現) 三:最小支撐樹(Prim,Kruskal算法) 2010-10-27 23:16 斯蒂芬
          toString沒有定義。
          不好使  回復  更多評論
            

          主站蜘蛛池模板: 玉树县| 兰溪市| 镇宁| 衡山县| 汉源县| 武陟县| 本溪市| 渝中区| 十堰市| 饶阳县| 常熟市| 全州县| 定结县| 金昌市| 孟连| 浙江省| 武平县| 繁昌县| 南陵县| 泰来县| 五常市| 阜宁县| 南和县| 玛多县| 沂南县| 于都县| 白水县| 佛冈县| 上栗县| 太谷县| 嘉峪关市| 大足县| 勃利县| 万州区| 延吉市| 泸水县| 嘉定区| 徐闻县| 尚义县| 嘉荫县| 安阳市|