图算法-Dijkstra算法
目录
- 图算法-Dijkstra算法
- 图算法-Floyd算法
- 图算法-Bellman-Ford算法
- 图算法-Prim算法
- 图算法-Kruskal算法
参考文献
https://www.cnblogs.com/ggzhangxiaochao/p/9070873.html
1 问题描述
- Kruskal算法是一种用来寻找最小生成树的算法,由Joseph Kruskal在1956年发表。
- 用来解决同样问题的还有Prim算法和Boruvka算法等。三种算法都是贪婪算法的应用。和Boruvka算法不同的地方是,Kruskal算法在图中存在相同权值的边时也有效。
- 当点少,但是关系复杂的时候,使用prim算法,进行点的贪心。
- 当点多,但是关系很稀疏的时候,使用kruskal算法那,进行边的贪心
2 算法原理
记Graph中有v个顶点,e个边
新建图Graphnew,Graphnew中拥有原图中相同的e个顶点,但没有边
将原图Graph中所有e个边按权值从小到大排序
循环:从权值最小的边开始遍历每条边。if这条边连接的两个节点于图Graphnew中不在同一个连通分量中,添加这条边到图Graphnew中。直至图Graph中所有的节点都在同一个连通分量中。
3 算法流程
首先第一步,我们有一张图Graph,有若干点和边

将所有的边的长度排序,用排序的结果作为我们选择边的依据。这里再次体现了贪心算法的思想。资源排序,对局部最优的资源进行选择,排序完成后,我们率先选择了边AD。

在剩下的变中寻找。我们找到了CE。这里边的权重也是5

依次类推我们找到了6,7,7,即DF,AB,BE。

下面继续选择, BC或者EF尽管现在长度为8的边是最小的未选择的边。但是现在他们已经连通了(对于BC可以通过CE,EB来连接,类似的EF可以通过EB,BA,AD,DF来接连)。所以不需要选择他们。类似的BD也已经连通了(这里上图的连通线用红色表示了)。最后就剩下EG和FG了。当然我们选择了EG。

4 算法效率
时间复杂度:$O(E*\log_2V)$
5 算法实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
| #include<iostream> #include<vector> #include<queue> #include<algorithm> using namespace std;
class Graph{ private: int vertex_num; int edge; vector<vector<int>> arc; public: Graph(); Graph(int vertex_num_,int edge_); void print_edge(); void print_arc(); void Dijkstra(int begin); void Floyd(); void Prim(int begin); void Kruskal(); };
Graph::Graph(){ this->vertex_num = 7; this->edge=12; this->arc = vector<vector<int>>(vertex_num,vector<int>(vertex_num,INT_MAX)); arc[0][1]=12; arc[1][0]=12; arc[0][6]=14; arc[6][0]=14; arc[0][5]=16; arc[5][0]=16; arc[1][2]=10; arc[2][1]=10; arc[1][5]=7; arc[5][1]=7; arc[2][3]=3; arc[3][2]=3; arc[2][4]=5; arc[4][2]=5; arc[2][5]=6; arc[5][2]=6; arc[3][4]=4; arc[4][3]=4; arc[4][5]=2; arc[5][4]=2; arc[4][6]=8; arc[6][4]=8; arc[5][6]=9; arc[6][5]=9; for(int i=0;i<vertex_num;i++){ arc[i][i]=0; } }
Graph::Graph(int vertex_num_,int edge_){ this->vertex_num=vertex_num_; this->edge=edge_; this->arc=vector<vector<int>>(vertex_num,vector<int>(vertex_num,INT_MAX)); int beg=0,end=0,weight=0; for(int i=0;i<edge_;i++){ cin>>beg>>end>>weight; arc[beg][end]=weight; arc[end][beg]=weight; } }
void Graph::print_edge(){ for(int i=0;i<vertex_num;i++){ for(int j=0;j<vertex_num;j++){ if(arc[i][j]<INT_MAX) cout<<"begin:"<<i<<"\tend:"<<j<<"\tweight:"<<arc[i][j]<<endl; } } }
void Graph::print_arc(){ for(int i=0;i<vertex_num;i++){ for(int j=0;j<vertex_num;j++){ cout<<arc[i][j]<<"\t"; } cout<<endl; } }
class SetUnion{ public: vector<int> vec; SetUnion(int n){ vec=vector<int>(n); for(int i=0;i<n;i++){ vec[i]=i; } } int find_r(int x){ if(x==vec[x])return x; else{ return find_r(vec[x]); } } void merge(int i,int j){ vec[find(i)]=find(j); } int find(int x){ if(x==vec[x]){ return x; } else{ vec[x]=find(vec[x]); return vec[x]; } }
};
struct Edge { int start; int end; int weight; Edge(int s,int e,int w){ start=s; end=e; weight=w; } bool operator<(const Edge& a)const{ return a.weight > weight; } };
void Graph::Kruskal(){ vector<Edge> result; vector<Edge> vec; for(int i=0;i<vertex_num;i++){ for(int j=i+1;j<vertex_num;j++){ if(arc[i][j]<INT_MAX){ vec.push_back(Edge(i,j,arc[i][j])); } } } sort(vec.begin(),vec.end());
SetUnion su(vertex_num); int k=0; for(int i=0;i<vec.size();i++){ Edge e = vec[i]; if(su.find(e.start)!=su.find(e.end)){ result.push_back(e); su.merge(e.start,e.end); } }
for(int i=0;i<result.size();i++){ cout<<result[i].start<<"\t"<<result[i].end<<"\t"<<result[i].weight<<endl; } } int main(){ Graph g; g.Kruskal(); return 0; }
|