最小生成树
Prim--类似dijkstra,按最短路增广,堆优化
Kruskal--边权排序,并查集判环,加n-1条边即可
动态最小--Kruskal+插入排序 O(n^2)
//Prim
//dis为连到最小生成树的最短距离
memset(dis,-1,sizeof(dis));
dis[1]=0,vis[1]=1;
priority_queue<pair<int,int> >q;
q.push(make_pair(0,1));//dis,pos
while(!q.empty()){
int Dis=q.top().first,u=q.top().second;
q.pop();
if(vis[u])continue;
vis[u]=1;
ans+=Dis;
for(i=head[u];i;i=next[i]){
int v=to[i];
if(!vis[v]&&(dist[v]>val[i]||dist[v]==-1)){
dist[v]=val[i];
q.push(make_pair(dist[v],v));
}
}
}
}
//Kruskal
memset(F,-1,sizeof(F));
sort(edge,edge+tol,cmp);
int cnt=0;//计算加入的边数
int ans=0;
for(int i=0;i<tol;i++)
{
int u=edge[i].u,v=edge[i].v,w=edge[i].w;
u=Find(u),v=Find(v);
if(u!=v)
{
ans+=w;
F[u]=v;
cnt++;
}
if(cnt==n-1)break;
}
动态最小生成树
#include<bits/stdc++.h>
#define N 10005
using namespace std;
int n,h,fa[N],pd,Max,sum;
struct Node{int x;int y;int w;}a[N];
int getfather(int x){//并查集
if(fa[x]==x) return x;
fa[x]=getfather(fa[x]);
return fa[x];
}
void Sort(Node cur)//插入排序
{
int i,j;
for(i=sum;i>=1;i--) if(a[i].w<=cur.w) break;
for(j=sum;j>=i+1;j--) a[j+1]=a[j];
a[i+1]=cur,sum++;
}
int Kruskal()
{
int ans=0,k=0;
for(int i=1;i<=sum;i++) fa[i]=i;
for(int i=1;i<=sum;i++){
int x=getfather(a[i].x),y=getfather(a[i].y);
if(x!=y) fa[x]=y,ans+=a[i].w,Max=a[i].w,k++;
if(k==n-1) break;
}
if(k<n-1) return 0;
return ans;
}
int main()
{
//freopen("1.in","r",stdin);
cin>>n>>h;
for(int i=1;i<=h;i++){
Node cur;
int ans;
cin>>cur.x>>cur.y>>cur.w;
if(pd&&cur.w>Max){cout<<ans<<endl;continue;}//如果插入的边
//比当前最小生成树的最大边还大,则不更新
Sort(cur);
if(ans=Kruskal()){cout<<ans<<endl;pd=1;}
else cout<<"-1"<<endl;
}
return 0;
}
次小生成树
int dis[N],used[N][N];//到最小生成树最短的距离
int vis[N],Map[N][N],Max[N][N];
//Map存边权,Max指i-j路径上的最大距离
int pre[N];//i的上一个点
int Prim()
{
for(int i=2;i<=n;i++) pre[i]=1,dis[i]=Map[1][i];
pre[1]=0,vis[1]=1,dis[1]=0;
for(int i=2;i<=n;i++){
int min_dis=inf,k;
for(int j=1;j<=n;j++){
if(!vis[j]&&min_dis>dis[j]){
min_dis=dis[j],k=j;
}
}
if(min_dis==inf) return -1;
vis[k]=1,ans+=min_dis;
used[k][pre[k]]=used[pre[k]][k]=1;
for(int j=1;j<=n;j++){
if (vis[j]&&used[j][k]==0) Max[j][k]=Max[k][j]=max(Max[j][pre[k]],dis[k]);
//计算两点之间若无连接,若连接上构成回路这条回路中最大的一条边,有动归的思想
if(!vis[j]&&dis[j]>dis[k]+Map[j][k]){
dis[j]=dis[k]+Map[j][k],pre[j]=k;
}
}
}
return ans;
}
int change(int min_ans)//最小生成树的权值和
{
int ans=inf;
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)
ans=min(ans,min_ans+Map[i][j]-Max[i][j]);
return ans;
}