最小完全圖(最小生成樹加邊成完全圖)


最小完全圖

 時間限制: 1 s
 空間限制: 128000 KB
題目描述 Description

若一個圖的每一對不同頂點都恰有一條邊相連,則稱為完全圖。

最小生成樹MST在Smart的指引下找到了你,希望你能幫它變成一個最小完全圖(邊權之和最小的完全圖)。

注意:必須保證這個最小生成樹MST對於最后求出的最小完全圖是唯一的。

輸入描述 Input Description

第一行一個整數n,表示生成樹的節點數。

接下來有n-1行,每行有三個正整數,依次表示每條邊的頂點編號和邊權。

(頂點的邊號在1-n之間,邊權<231)

輸出描述 Output Description

一個整數ans,表示以該樹為最小生成樹的最小完全圖的邊權之和。

樣例輸入 Sample Input

4

1 2 1

1 3 1

1 4 2

樣例輸出 Sample Output

12

數據范圍及提示 Data Size & Hint

30%的數據:n<1000;

100%的數據:n≤20000,所有的邊權<2^31。

題目鏈接:http://codevs.cn/problem/2796/


分析Kruskal算法可知,最小生成樹中的每一條邊,都是連接某兩個連通塊的所有邊中,最小的那一個。因此我們要造一個完全圖,連接這兩個連通塊的所有邊都必須大於最小生成樹中對應的邊。
所以對最小生成數中的邊按升序排列,依次維護加邊操作和對應連通塊中點的個數就行了。
#include<bits/stdc++.h>
#define N 20050
using namespace std;

long long pre[N];
long long num[N]={0};
void init()
{
    for(long long i=0;i<N;i++)pre[i]=i,num[i]=1;
}

long long Find(long long x)
{
    long long boss=x;
    while(pre[boss]!=boss)boss=pre[boss];
    
    while(x!=boss)
    {
        long long now=pre[x];
        pre[x]=boss;
        x=now;
    }
    return boss;
}

struct ss
{
    long long u,v,w;
    
    bool operator < (const ss&s) const
    {
        return w<s.w;
    }
};

ss edge[N];


int main()
{
    long long n;
    init();
    scanf("%lld",&n);
    for(long long i=1;i<n;i++)
    {
        scanf("%lld %lld %lld",&edge[i].u,&edge[i].v,&edge[i].w);
    }
    
    sort(edge+1,edge+n);
    
    long long ans=0;
    for(long long i=1;i<n;i++)
    {
        long long u=edge[i].u,v=edge[i].v;
        ans+=(edge[i].w+1)*(num[Find(u)]*num[Find(v)]-1);
        ans+=edge[i].w;
        num[Find(v)]+=num[Find(u)];
        pre[Find(u)]=Find(v);
    }
    printf("%lld\n",ans);
    return 0;
}
View Code

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM