Prime
算法核心:以点为参照,依次找到距离树最近的点,并入树中。无负边。
#include <iostream>
#include <cstring>
using namespace std;
const int INF = 0x3f3f3f3f;
const int N = 510;
int d[N]; //其他点到树上的距离
int g[N][N]; //已知的边长
bool flag[N]; //记录是否到树上
int n , m;
int Prime(){
//不连通返回INF 否则返回ans
int ans = 0;
memset(d,INF,sizeof d);
for(int i = 0 ; i<n ; i++){
int t = -1;
for(int j = 1 ; j<=n ; j++){ //找到树距离最小的点
if(!flag[j]&&(t==-1||d[j]<d[t])) //第一趟t=-1先忽略 因为d[t]没有初值
t = j;
}
if(i&&d[t]==INF) return INF; //树的第一个点还没有更新边 所以d[0]肯定是INF,所以先跳过
if(i) ans += d[t];
flag[t] = true;
for(int j = 1 ; j<=n ; j++) d[j] = min(d[j] , g[t][j]); //因为加入了新点 所以更新d数组
}
return ans;
}
int main(){
cin>>n>>m;
memset(g,INF,sizeof g);
//如果被录入则为true所以存在自环没什么影响
while(m--){
int x,y,z;
cin>>x>>y>>z;
g[x][y] = g[y][x] =min(z , g[x][y]); //无向 因为存在重边 所以要取最小值
}
int k = Prime();
if(k==INF) cout<<"impossible"<<endl;
else cout<<k<<endl;
return 0;
}
Kriskal
算法核心:以边为参照,将边按升序排序,然后找出最短的边组成完整的树。需要用到并查集。无负边
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 1e5+10 , M = 2e5;
const int INF = 0x3f3f3f3f;
int pre[N];
int m,n;
struct Edge{ //用于读取数据
int a,b,w;
bool operator<(const Edge &W) const { //重载运算符 ,保证长度顺序
return w<W.w;
}
}Edge[M];
int find(int x){ //查并集核心
if(pre[x]!=x) pre[x] = find(pre[x]);
return pre[x];
}
int Kruskal(){
sort(Edge+1,Edge+m+1); //对长度排序
for(int i = 1 ; i<=n ; i++) pre[i] = i; //初始化查并集
int ans = 0 , s = 0; //ans是总长度 ,s是并入树的边
for(int i = 1 ; i<=m ; i++){
auto t = Edge[i];
t.a = find(t.a); //对一条边的两个点分别找祖宗
t.b = find(t.b);
if(t.a!=t.b){ //如果不是同一个祖宗则不会形成环
pre[t.a] = t.b; //可以相连
ans+=t.w;
s++;
}
}
if(s!=n-1) return INF; //如果并入树的边数不等于点的个数减一说明没有连通
return ans;
}
int main()
{
cin>>n>>m;
for(int i = 1 ; i<=m ; i++){
int x,y,z;
cin>>x>>y>>z;
Edge[i] = {x,y,z};
}
int k = Kruskal();
if(k==INF) cout<<"impossible"<<endl;
else cout<<k<<endl;
return 0;
}