Vijos1579:宿命的PSS

背景

P.S.S:“我来自哪里?”
WH:“你来自一个图。”
P.S.S:“我是谁?”
WH:“你是最小生成树。”
P.S.S:“我又要到哪里去?”
WH:“你要成为一个最小完全图(边权之和最小的完全图)。”
P.S.S:“为……为什么啊?”
WH:“这是你的宿命!因为你无聊!!!P.S.S!”

描述

最小生成树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

思路:每次从最小生成树中选一个最小边添加到图中,设该边的权值为w,那么该边所连接的两个连通分量的结点之间的权值为w+1

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int MAXN=20005;
struct Edge{
    int u,v;
    ll w;
}es[MAXN];
bool operator<(Edge e1,Edge e2)
{
    return e1.w < e2.w;
}
int par[MAXN],tot[MAXN];
ll res;
void prep()
{
    for(int i=0;i<MAXN;i++)
    {
        par[i]=i;
        tot[i]=1;
    }
}
int fnd(int x)
{
    if(x==par[x])
        return x;
    return par[x]=fnd(par[x]);
}
void unite(int u, int v,ll w)
{
    int a=fnd(u);
    int b=fnd(v);
    res+=((tot[a]*tot[b]-1)*(w+1));
    par[b]=a;
    tot[a]+=tot[b];
}
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=0;i<n-1;i++)
    {
        scanf("%d%d%lld",&es[i].u,&es[i].v,&es[i].w);
    }
    sort(es,es+n-1);
    prep();
    for(int i=0;i<n-1;i++)
    {
        res+=es[i].w;
        unite(es[i].u,es[i].v,es[i].w);
    }
    printf("%lld\n",res);
    return 0;
} 

 

posted on 2016-04-06 21:29  vCoders  阅读(368)  评论(0编辑  收藏  举报

导航