定义
- 在无向图中 生成一棵树,这棵树涵盖所有顶点,且权值之和最小
性质
- 边数=n-1
- 对于给定的图,最小生成树可能不唯一,但是权值之和一定唯一
- 每一个结点都是平等的(因为来源于图)
- O(v2),可以用堆优化为O(VlogV+E)
代码
邻接矩阵
#include<algorithm>
using namespace std;
const int max_n = 30;
const int INF=0x3fffffff;
int n,G[max_n][max_n];
bool vis[max_n] = { false };
int d[max_n];//距离集合的最短距离
//prim算法
//邻接矩阵
void prim()
{
fill(d, d + n, INF);
//选出
d[0] = 0;
for (int j = 0; j < n ;j++)
{
int u = -1, min = INF;
//选出最近的
for (int i = 0; i < n; i++)
{
if (vis[i] == false && d[i] < min)
{
min = d[i];
u = i;
}
}
//加入集合 更新
if (u == -1)return;
vis[u] = true;
for (int i = 0; i < n; i++)
{
if (vis[i] == false && G[u][i] != INF && d[i] > G[u][i])
{
d[i] = G[u][i];
}
}
}
}
邻接表
#include<algorithm>
#include<vector>
using namespace std;
//最小生成树:在无向图中 生成一棵树,这棵树涵盖所有顶点,且权值之和最小
//1.边数=n-1
//2.对于给定的图,最小生成树可能不唯一,但是权值之和一定唯一
//3.每一个结点都是平等的(因为来源于图)
const int max_n = 30;
const int INF=0x3fffffff;
int n;
struct node
{
int v;
int dis;
};
vector<node*>Adj[max_n];
bool vis[max_n] = { false };
int d[max_n];//距离集合的最短距离
//prim算法
//邻接表
void prim()
{
fill(d, d + n, INF);
d[0] = 0;
for (int j = 0; j < n - 1; j++)
{
int u = -1, min = INF;
for (int i = 0; i < n; i++)
{
if (vis[i] == false && d[i] < min)
{
min = d[i];
u = i;
}
}
if (u == -1)return;
vis[u] = true;
for (int i = 0; i < Adj[u].size(); i++)
{
int v = Adj[u][i]->v;
int dis = Adj[u][i]->dis;
if (vis[v] == false && d[v] > dis)
{
d[v] = dis;
}
}
}
}
Kruskal算法
- 加最小边 然后判断有没有环
- 使用并查集 没有环:两个端点的根节点不同
#include<algorithm>
using namespace std;
const int max_n = 30;
const int max_e = 40;
int father[max_n];
int e,n;
struct edge
{
int s;
int d;
int dis;
};
edge edges[max_e];
bool cmp(edge e1,edge e2)
{
return e1.dis < e2.dis;
}
//找到根节点
int findFather(int v)
{
int x = v;
while (father[x] != x)
{
x = father[x];
}
return x;
}
//合并两个集合
bool Union(int x, int y)
{
int fx = findFather(x), fy = findFather(y);
if (fx != fy)
{
father[fy] = fx;
return true;
}
return false;
}
int kruskal()
{
sort(edges, edges + e, cmp);
int ans = 0;//权值之和
int cnt = 0;//边数
for (int i = 0; i < n; i++)
{
father[i] = i;
}
for (int i = 0; i < e; i++)
{
if (Union(edges[i].s, edges[i].d))//判断有没有环
{
ans += edges[i].dis;//选择这条边
cnt++;
}
if (cnt == n - 1)
{
break;
}
}
return ans;
}