最小生成树review
题目链接
最小生成树
Kruskal 适合点多的稀疏图O(mlogm)
#include<bits/stdc++.h>
using namespace std;
const int N = 2e6+9;
int n,m,s,cnt;
int fa[N];
struct pp {
int l,r,w;//w是路径长度
bool operator <(const pp &b)
{
return w < b.w;
}
}a[N];
inline int find(int x) { //并查集的模板,一直往上找父节点
return x==fa[x]?x:fa[x] = find(fa[x]);
}
void kruskal() {
for(int i=1; i<=m; i++) {
int v=find(a[i].l),u=find(a[i].r);//找父节点,看是否同根
if(v==u)continue; //已经被接在了树上,就不用接了
++cnt;
s+=a[i].w;
fa[u]=v;
if(cnt==n-1) return;
}
}
int main() {
ios::sync_with_stdio(false),cin.tie(0);
cin>>n>>m;
for(int i=1; i<=n; i++)
fa[i]=i;//初始化,自己是自己的父节点
for(int i=1; i<=m; i++)
cin>>a[i].l>>a[i].r>>a[i].w;
sort(a+1,a+m+1);
kruskal();
if(cnt==n-1)
cout<<s;
else cout<<"orz";
return 0;
}
prim堆优化,O(nlogn)-适合边多稠密图 (被卡可达到n2)
#include<bits/stdc++.h>
#define R register int//优化,可忽略
#define P pair <int,int>
using namespace std;
const int N = 1e5+9;
int k,n,m;
int cnt,sum,dis[N],vis[N];
vector <int> E[2*N];//存点
vector <int> W[2*N];//存边
inline void add(int u,int v,int w) {
E[u].push_back(v);//存点
W[u].push_back(w);//存边
}
priority_queue <P,vector<P>,greater<P> > q; //递减
inline void prim() { //神似dijskra
memset(dis,127,sizeof(dis)); //初始化
dis[1]=0;
q.push({dis[1],1});
while(!q.empty()&&cnt<n) {
int d=q.top().first,u=q.top().second;
q.pop();
if(vis[u]) continue;
cnt++;
sum+=d;
vis[u]=1; //处理重复和求距离
for(R i=0; i<E[u].size(); i++)//dijskra这里是循环找中界点,这里则直接找与该点相邻的边
if(W[u][i]<dis[E[u][i]]){
dis[E[u][i]]=W[u][i];
q.push({dis[E[u][i]],E[u][i]});
}
}
}
int main() {
scanf("%d%d",&n,&m);
for(R i=1; i<=m; i++) {
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
add(a,b,c);
add(b,a,c);
}
prim();
if (cnt==n)printf("%d",sum);
else printf("orz");
}
本文来自博客园,作者:InsiApple,转载请注明原文链接:https://www.cnblogs.com/InsiApple/p/16210732.html