tyvj1391走廊泼水节——kruskal
Posted Zinn
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了tyvj1391走廊泼水节——kruskal相关的知识,希望对你有一定的参考价值。
题目:http://www.joyoi.cn/problem/tyvj-1391
大意就是把一个树扩充成一个完全图,并且图中最小生成树仍是原来的树。
思路很巧妙,把边按权值从小到大排序,然后模拟加边的过程,并查集记录左右两边连通块的大小;
这样每新加一条边合并两个并查集(完全图),可知此时两边的图中每个点互相连边的最优选择就是连接这两个图的那条边的边权+1;
这样求最小生成树时要连接这两个连通块,则一定会选择原树边。
代码如下:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int const MAXN=6005; int t,n,ct,fa[MAXN],s[MAXN],ans; struct N{ int to,hd,w; N(int t=0,int h=0,int w=0):to(t),hd(h),w(w) {} }edge[MAXN<<1]; int find(int x) { if(fa[x]==x)return x; return fa[x]=find(fa[x]); } bool cmp(N x,N y) { return x.w<y.w; } int main() { scanf("%d",&t); while(t--) { ct=0;ans=0; scanf("%d",&n); int x,y,z; for(int i=1;i<n;i++) { scanf("%d%d%d",&x,&y,&z); edge[++ct]=N(x,y,z); fa[i]=i;s[i]=1; } fa[n]=n;s[n]=1;//!!! sort(edge+1,edge+ct+1,cmp); for(int i=1;i<n;i++) { int u=find(edge[i].to); int v=find(edge[i].hd); if(u!=v) { fa[u]=v; ans+=(s[u]*s[v]-1)*(edge[i].w+1); s[v]+=s[u]; } } printf("%d\n",ans); } return 0; }
以上是关于tyvj1391走廊泼水节——kruskal的主要内容,如果未能解决你的问题,请参考以下文章