题目描述
在一个初始化为空的无向图中,不断加入新边。如果当前图连通,就求出当前图最小生成树的总权值;否则,输出-1。
分析
目前已知的算法中,破圈算法是最快的。
破圈算法顾名思义,把边按照输入顺序插入树中,如果该边的两端点在同一颗树里,再插入这条边一定会形成环。破圈算法就是把环上权值最大的边删去,就能够维持树的边权尽量小。
//破圈算法yhn(找cch要对拍程序的时候用他的号交了一遍。。)
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define SF scanf
#define PF printf
void Read(int &x){
x=0;
char c;
bool flag=0;
while(c=getchar(),c!=EOF&&(c<'0'||c>'9')&&c!='-');
if(c=='-'){flag=1;c=getchar();}
x=c-'0';
while(c=getchar(),c!=EOF&&c>='0'&&c<='9') x=x*10+c-'0';
if(flag==1)x=-x;
}
#define MAXN 210
#define INF 0x3FFFFFFF
using namespace std;
int fa[MAXN],f[MAXN],val[MAXN],vis[MAXN],last[MAXN];
int get_fa(int x){
if(fa[x]==0)
return x;
fa[x]=get_fa(fa[x]);
return fa[x];
}
void update(int x,int y,int stop){
if(stop==x)
return ;
if(f[y]!=0)
update(y,f[y],stop);
val[y]=val[x];
f[y]=x;
}
int check(int x,int y,int z){
memset(vis,0,sizeof vis);
int maxl=-1,maxd,k;
int x1=x;
while(x1!=0){
vis[x1]=maxl;
last[x1]=maxd;
if(maxl<val[x1]){
maxl=val[x1];
maxd=x1;
}
x1=f[x1];
}
x1=y;
maxl=0;
while(x1!=0){
if(vis[x1]!=0){
if(maxl>vis[x1]){
vis[x1]=maxl;
last[x1]=maxd;
k=2;
}
else
k=1;
break;
}
vis[x1]=maxl;
last[x1]=maxd;
if(maxl<val[x1]){
maxl=val[x1];
maxd=x1;
}
x1=f[x1];
}
if(vis[x1]>z){
if(k==1){
update(y,x,last[x1]);
val[x]=z;
}
else{
update(x,y,last[x1]);
val[y]=z;
}
}
return max(vis[x1],z);
}
int sum,ins,n,m,x,y,z;
int main(){
Read(n),Read(m);
for(int i=1;i<=m;i++){
Read(x),Read(y),Read(z);
int u=get_fa(x);
int v=get_fa(y);
if(u!=v){
ins++;
update(x,y,-1);
val[y]=z;
fa[v]=u;
sum+=z;
}
else{
int s=check(x,y,z);
sum=sum+z-s;
}
if(ins<n-1)
PF("-1\n");
else
PF("%d\n",sum);
}
}