Prim求最小生成树
思路:和djstl算法求最短路径类似,都是进行n次循环,每次找到dist最小的点,然后更新其他点.但是有两点不同:
- 找到最小点t后,要判断dist[t]是否是无穷,如果是无穷,说明没有最小生成树
- sum+=dist[t];
#include<bits/stdc++.h>
using namespace std;
const int N = 1e3 + 10;
typedef long long ll;
typedef pair<int, int> pii;
int e[N*2],ne[N*2],h[N];
int w[N];
int dist[N];
int st[N];
int idx = 0;
int n,m;
void add(int a,int b,int c)
{
e[idx] = b;
w[idx] = c;
ne[idx] = h[a];
h[a] = idx++;
}
void prim()
{
dist[1] = 0;
int sum = 0;
for(int i =0;i<n;i++)
{
int t = -1;
for(int k = 1;k<=n;k++)
{
if(st[k])continue;
if(t==-1||(dist[k]<dist[t]))
{
t =k;
}
}
if(dist[t]==0x3f3f3f3f)
{
cout<<"impossible";
return ;
}
sum+=dist[t];
st[t] =1;
for(int j =h[t];j!=-1;j = ne[j])
{
int k = e[j];
dist[k] = min(dist[k],w[j]);
}
}
cout<<sum;
return ;
}
int main()
{
cin>>n>>m;
memset(h,-1,sizeof(h));
memset(dist,0x3f,sizeof(dist));
memset(w,0x3f,sizeof(w));
while(m--)
{
int a,b,c;
cin>>a>>b>>c;
add(a,b,c);
add(b,a,c);
}
prim();
}
Kruskal(核心思想:并查集)
思路: 用结构体将所有边存下来,并且把边按照从小到大的顺序排列,用变量cnt记录最小生成树的边数
再遍历所有的边,如果边上的两个点都在一个集合里面,就不加入最小生成树,反之就加入,
更新集合,生成树,边数
遍历完之后,如果最下生成树的边数小于n-1,就代表没有最小生成树
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
typedef long long ll;
typedef pair<int, int> pii;
int p[N];
int n, m;
struct edge
{
int a,b,w;
bool operator <(const edge&W)const
{
return w<W.w;
}
}e[N*2];
int find(int a)
{
if(p[a]!=a)
p[a] = find(p[a]);
return p[a];
}
void klusker()
{
sort(e,e+m);
for(int i =1;i<=n;i++)
p[i] = i;
int sum = 0;
int cnt = 0;
for(int i =0;i<m;i++)
{
int a = e[i].a;
int b = e[i].b;
int w = e[i].w;
int x = find(a);
int y = find(b);
if(x!=y)
{
sum+=w;
p[x] = y;
cnt++;
}
}
if(cnt<n-1)
{
cout<<"impossible";
}
else
cout<<sum;
}
int main()
{
cin>>n>>m;
for(int i = 0;i<m;i++)
{
int a,b,c;
cin>>a>>b>>c;
e[i] = {a,b,c};
}
klusker();
return 0;
}