1. 程式人生 > >CH6201走廊潑水節

CH6201走廊潑水節

多少 kruskal tor += ccf name 給定 nbsp http

題目鏈接:

CH6201

【簡化版題意】給定一棵N個節點的樹,要求增加若幹條邊,把這棵樹擴充為完全圖,並滿足圖的唯一最小生成樹仍然是這棵樹。求增加的邊的權值總和最小是多少。

輸入格式

本題為多組數據~
第一行t,表示有t組測試數據
對於每組數據
第一行N,表示水龍頭的個數(當然也是OIER的個數);
2到N行,每行三個整數X,Y,Z;表示水龍頭X和水龍頭Y有一條長度為Z的小道

輸出格式

對於每組數據,輸出一個整數,表示修建的所有道路總長度的最短值。

樣例輸入

2
3
1 2 2
1 3 3
4
1 2 3
2 3 4
3 4 5 

樣例輸出

4
17 

數據範圍與約定

  • 每個測試點最多10組測試數據
    50% n<=1500;
    100% n<=6000
    100% z<=100

樣例解釋

第一組數據,在2和3之間修建一條長度為4的道路,是這棵樹變成一個完全圖,且原來的樹依然是這個圖的唯一最小生成樹.

  

  • 思路:先將所有邊按邊權排序,然後執行一個類似於Kruskall的過程,每次掃描到邊(x,y,z)時,若x,y不在同一個集合,此時應該合並Sx,Sy,此時,對於x所在集合中除x之外的點u,y所在集合中除y之外的點v,完全圖中u與v之間肯定要連一條邊,有因為要保證邊(x,y)一定在最小生成樹中,就必須讓(x,y)是連接兩個集合的邊權最小的邊。所以(u,v)的邊權最小為z+1.而Sx與Sy之間最後一共會增加(size[x]*size[y]-1)條邊,所以把(z+1)*(size[x]*size[y]-1)累加到答案中即可

  代碼:

 1 #include <cstdio>
 2 #include <algorithm>
 3 #include <cctype>
 4 #include <cstring>
 5 #include <iostream>
 6 #include <queue>
 7 using namespace std;
 8 
 9 const int N=6010;
10 long long ans=0;
11 int fa[N],size[N],T,n;
12 struct E{int x,y,z;}e[N];
13
bool operator<(const E &n1,const E &n2){return n1.z<n2.z;} 14 15 inline int get(int x){ 16 if(x==fa[x]) return x; return fa[x]=get(fa[x]); 17 } 18 int main() 19 { 20 scanf("%d",&T); 21 while(T--) 22 { 23 scanf("%d",&n); 24 for(int i=1 ; i<n ; i++) scanf("%d %d %d",&e[i].x,&e[i].y,&e[i].z); 25 for(int i=1 ; i<=n ; i++) fa[i]=i,size[i]=1; 26 sort(e+1,e+n); ans=0; 27 for(int i=1 ; i<n ; i++) 28 { 29 int x=get(e[i].x),y=get(e[i].y); 30 if(x==y) continue; 31 fa[x]=y; ans+=(long long)(size[x]*size[y]-1)*(e[i].z+1); 32 size[y]+=size[x]; 33 } 34 printf("%lld\n",ans); 35 } 36 37 return 0; 38 }

CH6201走廊潑水節