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);
}
posted @ 2020-11-27 16:54  INFP  阅读(85)  评论(0编辑  收藏  举报