输入输出格式
输入格式:
第一行包含两个整数N、M,表示该图共有N个结点和M条无向边。(N<=5000,M<=200000)
接下来M行每行包含三个整数Xi、Yi、Zi,表示有一条长度为Zi的无向边连接结点Xi、Yi
输出格式:
输出包含一个数,即最小生成树的各边的长度之和;如果该图不连通则输出orz
Prim算法:
Prim算法就是定义mat用来存图,dist数组用来存每个点到最小生成树的最短距离,vis数组标记此点是否已经在最小生成树中了(防止出现环)。
实际操作就是先随便把一个点加入到生成树里(一般是第一个点),然后寻找与该点距离最短的点并加入,然后在寻找与1,2点相连最短的点,并加入到生成树中,就这样不断的加下去,直到加入的点数与原图一致终止;
可以自己手动模仿一下过程,其实还是好理解的!
Kruskal算法:
对边进行排序,依次加边,加边时需要判断是否在同一棵树,在同一颗树加边会产生环,如何判断是否在同一棵树?这里我们用到并查集,当当前边的左右端点不在同一棵树则可以进行合并,当加入的点数和给出的顶点数一致时就跳出循环,范围最小生成树的值,如果遍历完后还是不够给定的定点数,则其无法构成生成树!
1.每次加入前确保加入的权值比之前加入的权值要小,否则不加入;
如 第一次 给出 1-2边的权值为3, 然后某次加边操作说 1-2边权值为10, 这时候我们保留第一次的权值(保留权值较小的那次)
2.一般Prim适用于稠密图,用邻接矩阵存顶点;
3.Prim算法是存储顶点,Kruskal算法是存储边,注意给出的数据范围进行存储;
Prim算法:
#include
using namespace std;
#define INF 0x3f3f3f3f
int n, m, dist[5010], mat[5010][5010];
bool vis[5010];
void init(int k)
{
for(int i = 1; i<=k; i++)
{
for(int j = 1; j<=k; j++)
{
mat[i][j] = INF;
}
dist[i] = INF;
}
}
void Union(int x, int y, int val)
{
if(val < mat[x][y])
{
mat[x][y] = mat[y][x] = val;
}
}
int Prim()
{
int sum = 0;
dist[1] = 0;
for(int i = 1; i<=n; i++)
{
int min_dist = INF, min_vertex;
for(int j = 1; j <= n; j++)
{
if(!vis[j] && min_dist > dist[j])
{
min_dist = dist[j];
min_vertex = j;
}
}
vis[min_vertex] = 1;
sum += min_dist;
for(int j = 1; j <= n; j++)
{
if(!vis[j] && mat[min_vertex][j] < dist[j])
{
dist[j] = mat[min_vertex][j];
}
}
}
return sum;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n >> m;
init(n);
memset(vis, 0, sizeof(vis));
for(int i = 0; i<m; i++)
{
int x, y, val;
cin >> x >> y >> val;
Union(x, y, val);
}
cout << Prim() << endl;
return 0;
}
Kruskal算法:
#include
using namespace std;
#define MAX 200100
struct Node{
int x, y, val;
}S[MAX];
int pre[MAX];
bool cmp(Node a, Node b)
{
return a.val < b.val;
}
void init(int k)
{
for(int i = 0; i<k; i++)
pre[i] = i;
}
int Find(int x)
{
int r = x;
while(r != pre[r])
{
r = pre[r];
}
int i = x, j;
while(i != r)
{
j =pre[i];
pre[i] = r;
i = j;
}
return r;
}
int Kruskal(int n, int m)
{
int sum = 0, ans = 0;
for(int i = 0; i<m; i++)
{
int x = Find(S[i].x);
int y = Find(S[i].y);
if(x != y)
{
sum += S[i].val;
pre[x] = y;
ans++;
}
if(ans == n)
return sum;
}
return sum;
}
int main()
{
int n, m;
cin >> n >> m;
init(n);
for(int i = 0; i<m; i++)
{
cin >> S[i].x >> S[i].y >> S[i].val;
}
sort(S, S+m, cmp);
cout << Kruskal(n, m) << endl;
return 0;
}