053.最小生成树
最小生成树的特征
-
无向带权图
-
n个节点,n-1条边 -
所有节点连通
-
边权和最小
-
最小生成树一定是最小瓶颈树
-
最小生成树可能不止一棵
模板
kruskal
-
对边排序
-
并查集避免成环(并查集记得初始化)
-
选
n-1条边 -
O(n+m)+O(m*logm)
const int N=1e5+5;
const int M=1e5+5;
struct edge{
int u,v,w;
}e[M];
int fa[N];
void built(int n){
for(int i=1;i<n;++i){
fa[i]=i;
}
}
int find(int x){
if(fa[x]!=x){
fa[x]=find(fa[x]);
}
return fa[x];
}
bool merge(int a,int b){
int A=find(a);
int B=find(b);
if(A==B)return 0;
fa[A]=B;
return 1;
}
int kruskal(int n,int m){
sort(e,e+m,[&](auto a,auto b){return a.w<b.w;});
int sum=0;
int cnt=0;
built(n);
for(int i=0;i<m;++i){
if(merge(e[i].u,e[i].v)){
sum+=e[i].w;
cnt++;
}
}
return cnt==n-1?sum:-1;
}
void solve(){
int n,m;
cin>>n>>m;
for(int i=0;i<m;++i){
cin>>e[i].u>>e[i].v>>e[i].w;
}
int ans=kruskal(n,m);
}
prim
-
小根堆存边
-
vis[]避免成环 -
选
n-1条边 -
O(n+m)+O(m*logm)
const int N=1e5+5;
int vis[N];
struct edge{
int to,cost;
};
vector<edge>gra[N];
int prim(int n){
auto cmp=[](edge a,edge b){return a.cost>b.cost;};
priority_queue<edge,vector<edge>,decltype(cmp)>pq(cmp);
vis[1]=1;
for(auto edge:gra[1]){
pq.push(edge);
}
int sum=0;
int cnt=0;
while(pq.size()){
auto e=pq.top();
pq.pop();
if(!vis[e.to]){
vis[e.to]=1;
sum+=e.cost;
cnt++;
for(auto nex:gra[e.to]){
pq.push(nex);
}
}
}
return (cnt==n-1)?sum:-1;
}
void solve(){
int n,m,u,v,w;
cin>>n>>m;
for(int i=1;i<=n;++i){
vis[i]=0;
}
for(int i=0;i<m;++i){
cin>>u>>v>>w;
gra[u].push_back({v,w});
gra[v].push_back({u,w});
}
int ans=prim(n);
}
prim堆优化版
-
手写优化堆
-
堆里的元素数量不会超过节点总数
-
来到当前边,更新堆里边的信息
-
O(n+m)+O((m+n)*logn)
const int N=5005;
const int M=400005;
int n,m;
int u,v,w;
int head[N];
int nex[M];
int to[M];
int weight[M];
int tot;
int heap[N][2];
int tag[N];
int siz;
int cnt;
void built(){
tot=1;
siz=0;
cnt=0;
for(int i=1;i<=n;++i){
head[i]=0;
tag[i]=-1;
}
}
void addEdge(int u,int v,int w){
nex[tot]=head[u];
to[tot]=v;
weight[tot]=w;
head[u]=tot++;
}
void swap(int i,int j){
int a=heap[i][0];
int b=heap[j][0];
tag[a]=j;
tag[b]=i;
int t0=heap[i][0];
heap[i][0]=heap[j][0];
heap[j][0]=t0;
int t1=heap[i][1];
heap[i][1]=heap[j][1];
heap[j][1]=t1;
}
void swim(int i){
while(heap[i][1]<heap[(i-1)/2][1]){
swap(i,(i-1)/2);
i=(i-1)/2;
}
}
void sink(int i){
int l=2*i+1;
while(l<siz){
int best=l+1<siz&&heap[l+1][1]<heap[l][1]?l+1:l;
if(heap[best][1]>=heap[i][1])return;
swap(i,best);
i=best;
l=2*i+1;
}
}
void pop(){
u=heap[0][0];
w=heap[0][1];
swap(0,--siz);
sink(0);
tag[u]=-2;
cnt++;
}
void update(int e){
int v=to[e];
int w=weight[e];
if(tag[v]==-1){
heap[siz][0]=v;
heap[siz][1]=w;
tag[v]=siz++;
swim(tag[v]);
}
else if(tag[v]!=-2){
heap[tag[v]][1]=min(w,heap[tag[v]][1]);
swim(tag[v]);
}
}
int prim(){
cnt=1;
tag[1]=-2;
for(int e=head[1];e;e=nex[e]){
update(e);
}
int ans=0;
while(siz){
pop();
ans+=w;
for(int e=head[u];e;e=nex[e]){
update(e);
}
}
return ans;
}
void solve(){
cin>>n>>m;
built();
for(int i=0;i<m;++i){
cin>>u>>v>>w;
addEdge(u,v,w);
addEdge(v,u,w);
}
int ans=prim();
if(cnt==n)cout<<ans;
else cout<<"orz";
}
习题
const int N=305;
const int M=8005;
struct edge{
int u,v,w;
}e[M];
int fa[N];
void built(int n){
for(int i=1;i<n;++i){
fa[i]=i;
}
}
int find(int x){
if(fa[x]!=x){
fa[x]=find(fa[x]);
}
return fa[x];
}
bool merge(int a,int b){
int A=find(a);
int B=find(b);
if(A==B)return 0;
fa[A]=B;
return 1;
}
int kruskal(int n,int m){
sort(e,e+m,[&](auto a,auto b){return a.w<b.w;});
int ans=0;
built(n);
for(int i=0;i<m;++i){
if(merge(e[i].u,e[i].v)){
ans=max(ans,e[i].w);
}
}
return ans;
}
void solve(){
int n,m;
cin>>n>>m;
for(int i=0;i<m;++i){
cin>>e[i].u>>e[i].v>>e[i].w;
}
int ans=kruskal(n,m);
cout<<n-1<<' '<<ans;
}
const int N=305;
struct edge{
int u,v,w;
}e[N*N];
int fa[N];
int find(int x){
if(x!=fa[x]){
fa[x]=find(fa[x]);
}
return fa[x];
}
bool merge(int a,int b){
int A=find(a);
int B=find(b);
if(A==B)return 0;
fa[A]=B;
return 1;
}
void solve(){
int n,v,tot=0;
cin>>n;
for(int i=0;i<n;++i){
cin>>v;
e[tot++]={i,n,v};
}
for(int i=0;i<n;++i){
for(int j=0;j<n;++j){
cin>>v;
e[tot++]={i,j,v};
}
}
sort(e,e+tot,[&](auto a,auto b){return a.w<b.w;});
for(int i=0;i<=n;++i){
fa[i]=i;
}
int ans=0;
for(int i=0;i<tot;++i){
if(merge(e[i].u,e[i].v)){
ans+=e[i].w;
}
}
cout<<ans;
}
class Solution {
struct edge{
int u,v,w;
};
int dis(int i,int j,vector<vector<int>>& p){
return abs(p[i][0]-p[j][0])+abs(p[i][1]-p[j][1]);
}
vector<int>fa;
void built(int n){
fa.resize(n);
for(int i=0;i<n;++i){
fa[i]=i;
}
}
int find(int x){
if(x!=fa[x]){
fa[x]=find(fa[x]);
}
return fa[x];
}
bool merge(int a,int b){
int A=find(a);
int B=find(b);
if(A==B)return 0;
fa[A]=B;
return 1;
}
public:
int minCostConnectPoints(vector<vector<int>>& points) {
int n=points.size();
built(n);
vector<edge>e;
for(int i=0;i+1<n;++i){
for(int j=i+1;j<n;++j){
e.push_back({i,j,dis(i,j,points)});
}
}
sort(e.begin(),e.end(),[&](auto a,auto b){return a.w<b.w;});
int ans=0;
for(auto x:e){
if(merge(x.u,x.v)){
ans+=x.w;
}
}
return ans;
}
};
I am the bone of my sword

浙公网安备 33010602011771号