CF875F
我们把两个潜在丈夫连边,选了两个潜在丈夫,等价于选了一个公主
我们先考虑树的情况,选了 \(k\) 条边连接 \(k+1\) 个点,那么我们可以舍弃一个点(一个王子),剩下的 \(k\) 个王子可以完全匹配这 \(k\) 个公主
如果增加一条边,\(k+1\)个王子和\(k+1\)个公主,也是可以匹配的,这玩意就是个基环树
魔改 \(kruskal\)
令 \(x=find(e[i].u),y = find(e[i].v)\),\(d\)数组表示\(i\)是否是基环树,\(0\)无环,\(1\)有环,众所周知
树+树=树,基环树+树=基环树
\(1.x\not=y\&\&(d[x]~||~d[y])=1\),说明至少有一个不是基环树,可以合成一个树或基环树,加边权,\(d[x]=d[x]~and~d[y]\)
\(2.x=y\),\(d[x]\)只能等于\(0\),即树,加一条边成基环树,\(d[x]\)变成\(1\)
struct Edge{int u,v,w;}e[N<<1]; int tot;
inline bool cmp(Edge a,Edge b){return a.w > b.w;}
int fa[N],n,m,num;bool d[N]; int ans;
int find(int x){return fa[x] == x ? x : fa[x] = find(fa[x]);}
int main(){
n = read(); m = read();
for(int i = 1;i <= m;++i){
e[i].u = read(); e[i].v = read(); e[i].w = read();
}
sort(e + 1,e + m + 1,cmp);
for(int i = 1;i <= n;++i) fa[i] = i,d[i] = 1;
for(int i = 1;i <= m;++i){
int u = find(e[i].u),v = find(e[i].v);
if(u != v && (d[u] || d[v]))
fa[v] = u,ans += e[i].w,d[u] = d[u]&d[v];
else if(u == v && d[u]) d[u] = 0,ans += e[i].w;
}
printf("%d\n",ans);
}