最小生成树就是找到没有回路的一条路径,而且权值相加最小
主要有prim算法和kruskal算法
A B 5
A D 2
A E 7
B D 3
D E 1
B C 1
E C 9
E F 4
E G 3
F G 1
prim算法
prim算法主要运用贪心的思想
1,确定起始点,添加到树里
2,将里树最近的一条路径添加进去(如果相同则任意一个都行)
3,不断重复2直到覆盖到所有节点
#include <bits/stdc++.h>
using namespace std;
string begin = "A";
int prim(map<string,map<string,int>> m)
{
int res = 0;//最小生成树的权值
set<string> check;//树中的节点
map<string,int> dis;//存储最小的边
//初始化
for(auto elem : m) dis.insert({elem.first,99999});
check.insert(::begin);
dis[::begin] = 0;
for(auto elem : m[::begin])
{
if(dis[elem.first] > elem.second) dis[elem.first] = elem.second;
}
while(check.size() != m.size())
{
string s;
int min = 999999;
for(auto elem : dis)
{
if(check.find(elem.first) == check.end() && elem.second < min)
{
s = elem.first;
min = elem.second;
}
}
check.insert(s);
//更新dis
for(auto elem : m[s])
{
if(dis[elem.first] > elem.second) dis[elem.first] = elem.second;
}
res += min;
}
return res;
}
int main()
{
map<string,map<string,int>> m;
for(int i = 0;i < 10;++i)
{
string x,y;
int num;
cin >> x >> y >> num;
m[x].insert({y,num});
m[y].insert({x,num});
}
cout << prim(m);
return 0;
}
kruskal算法
主要涉及到一个查并集的操作
1,将所有边从小到达排序
2,从最小的边开始遍历,如果左右节点祖先一样,就证明会构成回路,如果不一样,就添加到最小生成树中
3,直到遍历结束,成功的边就是最小生成树了
#include <bits/stdc++.h>
using namespace std;
int father[999];
int find_father(int e)
{
while(e != father[e]) e = father[e];
return e;
}
int kruskal(map<string,map<string,int>> m)
{
for(int i = 0;i < 999;++i) father[i] = i;
int res = 0;//最小生成树的权值
multimap<int,pair<string,string>> grap;//存储所以的边
//初始化
for(auto elem1 : m)
{
for(auto elem2 : elem1.second)
{
grap.insert({elem2.second,{elem1.first,elem2.first}});
}
}
//查并集
for(auto elem : grap)
{
string x = elem.second.first;
string y = elem.second.second;
//判断是否构成闭环
if(find_father(x[0]) == find_father(y[0]))
{
continue;
}
//添加边
father[find_father(y[0])] = x[0];
res += elem.first;
}
return res;
}
int main()
{
map<string,map<string,int>> m;
for(int i = 0;i < 10;++i)
{
string x,y;
int num;
cin >> x >> y >> num;
m[x].insert({y,num});
m[y].insert({x,num});
}
cout << kruskal(m);
return 0;
}