CH6201走廊潑水節
阿新 • • 發佈:2019-01-31
多少 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]; 13bool 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走廊潑水節