您的位置:首页 > 其它

最小生成树(先写个prim,kruscal)

2017-12-14 15:40 337 查看
概念:

生成树:一个连通图的生成树是指一个连通子图,它含有图中全部n个顶点,但只有足以构成一棵树的n-1条边。一颗有n个顶点的生成树有且仅有n-1条边,如果生成树中再添加一条边,则必定成环。

最小生成树:在连通网的所有生成树中,所有边的代价和最小的生成树,称为最小生成树。

一、kruscal

算法流程:

此算法可以称为“加边法”,初始最小生成树边数为0,每迭代一次就选择一条满足条件的最小代价边,加入到最小生成树的边集合里。

1. 把图中的所有边按代价从小到大排序;

2. 把图中的n个顶点看成独立的n棵树组成的森林;

3. 按权值从小到大选择边,所选的边连接的两个顶点ui,vi,应属于两颗不同的树,则成为最小生成树的一条边,并将这两颗树合并作为一颗树。

4. 重复(3),直到所有顶点都在一颗树内或者有n-1条边为止。



代码:

//Kruscal.h

#ifndef __KRUSKAL_H
#define __KRUSKAL_H
#include <vector>
using namespace std;
struct edge
{
int source;
int destination;
int weight;
};
typedef struct edge edge;
void sortEdge(vector<edge>& vecedge);
void KruskalAcc(vector<edge>& vecedge, int numOfNode);

#endif


//Kruscal.cc

#include "Kruskal.h"
#include <cstdlib>
#include <iostream>
using namespace std;
int compar(const void* p1, const void* p2)
{
return (*(edge*)p1).weight - (*(edge*)p2).weight;
}

int Parent(vector<int>& parent, int i)
{
if (i != parent[i])
{
parent[i] = Parent(parent, parent[i]);
}
return parent[i];
}

void sortEdge(vector<edge>& vecedge)
{
qsort(&*vecedge.begin(), vecedge.size(), sizeof(edge), compar);
}
void KruskalAcc(vector<edge>& vecedge, int numOfNode)
{
sortEdge(vecedge);
if (numOfNode < 2)
{
return;
}
vector<int> parent(numOfNode, 0);
for (int i = 0; i < numOfNode; ++i)
{
parent[i] = i;
}
int senlin = numOfNode;
vector<edge> res;
for (int i = 0; i < vecedge.size() && senlin>1; ++i)
{
const edge& e = vecedge[i];
int m = Parent(parent, e.source);
int n = Parent(parent, e.destination);
if (m!=n)
{
parent
= m;
res.push_back(e);
--senlin;
}
}
for (int i = 0; i < res.size(); ++i)
{
cout << res[i].source << "----" << res[i].destination <<":    "<<res[i].weight<< endl;
}
cout << endl;

}


//main.cc

#include "Kruskal.h"

#include <stdlib.h>
#include <iostream>
using namespace std;

int main()
{
//testThrowCoins();
int nodeOfnumber;
vector<edge> input;
cin >> nodeOfnumber;
edge tmp;
while (cin >> tmp.source >> tmp.destination >> tmp.weight)
{
input.push_back(tmp);
}
KruskalAcc(input, nodeOfnumber);

//testDijkstra();
system("pause");
return 0;


Prim

此算法可以称为“加点法”,每次迭代选择代价最小的边对应的点,加入到最小生成树中。算法从某一个顶点s开始,逐渐长大覆盖整个连通网的所有顶点。

1图的所有顶点集合为V;初始令集合u={s},v=V−u;

2在两个集合u,v能够组成的边中,选择一条代价最小的边(u0,v0),加入到最小生成树中,并把v0并入到集合u中。

3重复上述步骤,直到最小生成树有n-1条边或者n个顶点为止。



代码:

//Prim.h

#ifndef __PRIM_H
#define __PRIM_H
#include <vector>
using namespace std;
void Prim(vector< vector<int> >& vec, int source);

#endif


//Prim.cc

#include "Prim.h"

#include <assert.h>
#include <stdint.h>
#include <iostream>

void Prim(vector< vector<int> >& vec,int source)
{
int siz = vec.size();
assert(siz >= 2);
vector<int> visited(siz, 0);
visited[source] = 1;
vector<int> dist(siz, INT_MAX);
vector<int> prev(siz, -1);

dist[source] = 0;

vector<int> res;
res.push_back(source);

int nodeleave = siz - 1;
while (nodeleave > 0)
{
//1、更新
int min = INT_MAX;
int next = -1;
for (int i = 0; i < siz; ++i)
{
if (visited[i]==1) continue;
if (vec[source][i] < dist[i])
{
prev[i] = source;
dist[i] = vec[source][i];
}
if (dist[i] < min)
{
min = dist[i];
next = i;
}
}
--nodeleave;
res.push_back(next);
source = next;
visited[source] = 1;
}
for (int i = 0; i < siz; ++i)
{
cout << res[i] << "\t";
}
cout << endl;
for (int i = 0; i < siz; ++i)
{
cout << prev[i] << "\t";
}
cout << endl;

}


//main.cc

#include "Prim.h"

#include <stdlib.h>
#include <iostream>
using namespace std;

int main()
{

vector< vector<int> > input = {
{ 0, 6, 1, 5, INT_MAX, INT_MAX },
{ 6, 0, 5, INT_MAX, 3, INT_MAX },
{ 1, 5, 0, 5, 6, 4 },
{ 5, INT_MAX, 5, 0, INT_MAX, 2 },
{ INT_MAX, 3, 6, INT_MAX, 0, 6 },
{ INT_MAX, INT_MAX, 4, 2, 6, 0 }
};
Prim(input, 0);

//system("pause");
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: