转载一下YH大佬的blog地址http://blog.csdn.net/jokercold
。。
直译小丑严寒2333
以及HK大佬
http://blog.csdn.net/yuyaohekai
宿命的PSS
题目描述
最小生成树P.S.S在宿命的指引下找到了巫师Kismi。P.S.S希望Kismi能帮自己变成一个完全图。Kismi由于某些不可告人的原因,把这件事交给了你。 PS: 可以保证,这个最小生成树对于最后求出的完全图是唯一的。
输入
输入的第一行是一个整数n,表示生成树的节点数。 接下来有n-1行,每行有三个正整数,依次表示每条边的端点编号和边权。 (顶点的边号在1-n之间,边权< maxint)
输出
一个整数ans,表示以该树为最小生成树的最小完全图的边权之和。
样例输入
3 1 2 4 2 3 7
样例输出
19
这道题题面就不清,也没有说明应该求的是最小完全图个边之和
根据克鲁斯卡尔思想,我们每次取其中边权最小不在已知最小生成树中的边加入,即可得到最小生成树
所以这道题若我们已插入属于最小生成树的(u,v)这条边,那么和u相连的所有元素和与v相连的所有元素的距离至少大于这个距离
所以先对所有最小生成树的边排个序
对于每条最小生成树上的边
ans+=(Edge[i].val+1)*(the number of the points connected to Edge[i].u+ to Edge[i].v-1);再加上本来的边权Edge[i].v。
HK大佬的代码,贴一下
#include<iostream> #include<cstdio> #include<algorithm> using namespace std; int n,m,f[20010]; long long number[20010]; struct node { int u,v; long long z; }a[20010]; bool cmp(node a,node b) { if (a.z<b.z) return true; return false; } int get(int x) { if (f[x]==x) return x;else f[x]=get(f[x]); return f[x]; } int main() { scanf("%d",&n); long long ans=0; for (int i=1;i<=n-1;i++) { scanf("%d%d%lld",&a[i].u,&a[i].v,&a[i].z); ans+=a[i].z; } sort(a+1,a+n,cmp); for (int i=1;i<=n;i++) f[i]=i,number[i]=1; for (int i=1;i<=n-1;i++) { if (get(a[i].u)!=get(a[i].v)) { long long num=number[get(a[i].u)]; ans+=(a[i].z+1)*(number[get(a[i].u)]*number[get(a[i].v)]-1); f[get(a[i].u)]=get(a[i].v); number[get(a[i].v)]+=num; } } printf("%lld\n",ans); return 0; }
时间: 2024-10-29 19:10:58