暢通工程 (並查集or最小生成樹)
阿新 • • 發佈:2018-11-09
省政府“暢通工程”的目標是使全省任何兩個村莊間都可以實現公路交通(但不一定有直接的公路相連,只要能間接通過公路可達即可)。經過調查評估,得到的統計表中列出了有可能建設公路的若干條道路的成本。現請你編寫程式,計算出全省暢通需要的最低成本。
Input
測試輸入包含若干測試用例。每個測試用例的第1行給出評估的道路條數 N、村莊數目M ( < 100 );隨後的 N
行對應村莊間道路的成本,每行給出一對正整數,分別是兩個村莊的編號,以及此兩村莊間道路的成本(也是正整數)。為簡單起見,村莊從1到M編號。當N為0時,全部輸入結束,相應的結果不要輸出。
Output
對每個測試用例,在1行裡輸出全省暢通需要的最低成本。若統計資料不足以保證暢通,則輸出“?”。
Sample Input
3 3
1 2 1
1 3 2
2 3 4
1 3
2 3 2
0 100
Sample Output
3
?
分析:其實這道題想考察的是用Kruskal的方法求最小生成樹,另外又讓你判斷了一下例項是否存在最小生成樹。
那麼在最後用一個迴圈來判斷一下他們的根節點是否相同就行了,即是否都在一棵樹上。如果不相同說明統計的資料不足,輸出“?”。
#include<stdio.h> struct edge { int u; int v; int w; }; struct edge e[101]; int m,n; int f[101] = {0},sum,count = 0; void quicksort(int left, int right) { int i,j; struct edge t; if(left > right) return ; i = left; j = right; while(i != j) { while(e[j].w >= e[left].w && i < j) j --; while(e[i].w <= e[left].w && i < j) i ++; if(i < j) { t = e[i]; e[i] = e[j]; e[j] = t; } } t = e[left]; e[left] = e[i]; e[i] = t; quicksort(left,i-1); quicksort(i+1,right); return ; } int getf(int v) { if(f[v] == v) return v; else { f[v] = getf(f[v]); return f[v]; } } int merge(int v,int u) { int t1,t2; t1 = getf(v); t2 = getf(u); if(t1 != t2) { f[t2] = t1; return 1; } return 0; } int main() { int i,flag; while(scanf("%d%d",&m,&n), m != 0) { sum = 0;count = 0;flag = 0; for(i = 1; i <= m; i ++) scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w); quicksort(1,m); for(i = 1; i <= n; i ++) f[i] = i; for(i = 1; i <= m; i ++) { if(merge(e[i].u,e[i].v)) { count ++; sum += e[i].w; } } for(i = 2; i <= n; i ++) { if(getf(1) != getf(i)) flag = 1; } if(flag == 1) printf("?\n"); else printf("%d\n",sum); } return 0; }