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 ot=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
",ans);
}
原文地址:https://www.cnblogs.com/shikeyu/p/14049063.html