学完最小生成树又马上开始学最短路径,两者关系开始混淆
此篇是帮助我本人对这两个算法有所了解与辨别
最短路径是对于一个图的两个结点而言最短的。在一个图中,结点A通过某些结点和边可以走到结点B,那这些结点和边就组成一条A到B的路径,A到B的最短路径就是A到B的所有路径中边zhuan值总和最小的那一条(或多条)。
最小生成树是对于一个图本身而言的。对于一个有n个结点的无向连通图(边没有方向,任意两点之间都存在路径可以到达),必然可以去掉某些边,使得最终剩下n-1条边,并且n个结点仍然是连通的,这n个结点和n-1条边组成了原图的一个生成树,而最小生成树就是所有可能的生成树中n-1条边的shu值总和最小的那一个(或多个)。
总结一句话,最短路径是到其他点最短,而最小生成树是将多余的边不要使得总的权值最小
最小生成树常用算法有:prim,kruskal
prim
- 初始化:u= {u0},tree = {};
- 如u合集输出最小生成树并结束
- 在所有的两栖边中找一条权最小的边将边(u,v)加入边集tree并将顶点加入集合u中
- 由于新点加入状态变化对u与v-u两栖边调整
- 转2
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define maxn 30
#define inf 100000
int road[maxn][maxn]; //邻接矩阵
int dis[maxn]; //判断行,从中取出最小点加入vis
bool vis[maxn]; //true代表已经纳入,false代表是为纳入
int n;
void prim()
{
int minn, v;
for(int i = 0; i < n; i++)
{
dis[i] = road[0][i]; //每个点与起点的距离
vis[i] = false;
}
for(int i = 1; i <= n; i++)//包括第一个点在内,一共要纳入n个点
{
minn = inf;
for(int j = 0; j < n; j++)
{
if(!vis[j] && minn > dis[j]) //每次找出未纳入顶点集与已知顶点集构成的权值最小的一条边
{
v = j;
minn = dis[j];
}
}
vis[v] = true;//把该顶点纳入已知集合 ,v就是未纳入顶点最短距离的点
for(int j = 0; j < n; j++)//更新与未纳入集合中的顶点的边的最小权值
{
if(vis[j]==false && dis[j] > road[v][j]) //未纳入 且 每个点与起点的距离大于新纳入的顶点v的距离
dis[j] = road[v][j]; //更新新的短距离
}
}
int ans;
for(int i = 1; i < n; i++)
ans += dis[i]; //将每个点(除起点)的距离累加
printf("%d\n",ans);
}
int main()
{
int n;
while(~scanf("%d",&n)&&n!=0)
{
for(int i = 0; i < n; i++) //初始化邻接矩阵
road[i][i] = 0;
for(int i = 1; i < n; i++) //构造邻接矩阵
{
for(int j=1;j<=n;j++)
scanf("%d",&road[i][j]);
}
/*for(int i=0;i<n;i++)
{
for(int j =0;j<n;j++)
printf("%d ",road[i][j]);
printf("\n");
} */
prim();
}
return 0;
}
kruskal算法
贪心法使每条边权值尽可能少, 适用稀疏图
- 判连通
- 连通两分量运用并查集 先造只含n个顶点的子图,从其最小边开始,若其不使之产生回路则加上这条边,直到加至n-1条边为止
#include <stdio.h>
#include <string.h>
#include <math.h>
#include<bits/stdc++.h>
using namespace std;
int n,m,i,j,sum,cnt;
int parent[10000];
void init(){
for(i=0;i<10000;i++)
parent[i] = i;
}
int find(int n)
{
int temp,son;
while(n!=parent[n])
n = parent[n];
while(son!=n)
{
temp = parent[son];
parent[son]=n;
son = temp;
}
return n;
}
int join(int a,int b)
{
int owner1 = find(a),owner2 = find(b);
if(owner1!=owner2)
{
parent[owner1] = owner2;
return 1;
}
return 0;
}
struct purchase{
int x,y,cost;
}p[40000];
inline bool cmp(purchase a,purchase b)
{
return a.cost<b.cost;
}
int main()
{
cin>>n>>m;
for(j=1;j<=m;j++)
{
cin>>p[j].x>>p[j].y>>p[j].cost;
}
sort(p+1,p+m,cmp);
init();
for(i=1;i<=m;i++)
{
if(join(p[i].x,p[i].y))
{
sum+=p[i].cost;
cnt++;
}
if(cnt==n-1)
break;
}
cout<<sum;
return 0;
}