給定一個帶權無向圖,如果是連通圖,則至少存在一棵最小生成樹,有時最小生成樹並不唯一。本題就要求你計算最小生成樹的總權重,並且判斷其是否唯一。
輸入格式:
首先第一行給出兩個整數:無向圖中頂點數 N(≤)和邊數 M。隨后 M 行,每行給出一條邊的兩個端點和權重,格式為“頂點1 頂點2 權重”,其中頂點從 1 到N 編號,權重為正整數。題目保證最小生成樹的總權重不會超過 230。
輸出格式:
如果存在最小生成樹,首先在第一行輸出其總權重,第二行輸出“Yes”,如果此樹唯一,否則輸出“No”。如果樹不存在,則首先在第一行輸出“No MST”,第二行輸出圖的連通集個數。
輸入樣例 1:
5 7
1 2 6
5 1 1
2 3 4
3 4 3
4 1 7
2 4 2
4 5 5
輸出樣例 1:
11
Yes
輸入樣例 2:
4 5
1 2 1
2 3 1
3 4 2
4 1 2
3 1 3
輸出樣例 2:
4
No
輸入樣例 3:
5 5
1 2 1
2 3 1
3 4 2
4 1 2
3 1 3
輸出樣例 3:
No MST 2
對於最小生成樹如果不唯一,那就說明最小生成樹中的某條邊可以換成其他一條同權值的邊且保證仍然是最小生成樹,如此只需要對最小生成樹中權值不唯一的邊進行刪除並重新進行最小生成樹的查找即可。
代碼:
#include <cstdio> #include <algorithm> using namespace std; int n,m,c,num; struct line { int u,v,w; }r[130000]; int f[501],tag[130000],tn,flag; void init() { for(int i = 1;i <= n;i ++) { f[i] = i; } } int getf(int k) { return k == f[k] ? f[k] : (f[k] = getf(f[k])); } bool cmp(const line &a,const line &b) { return a.w < b.w; } bool check() { for(int i = 0;i < tn;i ++) { init(); int d = 0,e = 0; for(int j = 0;j < m;j ++) { if(j == tag[i]) continue; if(getf(r[j].u) != getf(r[j].v)) { f[getf(r[j].u)] = getf(r[j].v); d += r[j].w; e ++; } } if(e == n - 1 && d == c) return 1; } return 0; } int main() { scanf("%d%d",&n,&m); init(); for(int i = 0;i < m;i ++) { scanf("%d%d%d",&r[i].u,&r[i].v,&r[i].w); } sort(r,r + m,cmp); for(int i = 0;i < m;i ++) { if(getf(r[i].u) != getf(r[i].v)) { f[getf(r[i].u)] = getf(r[i].v); c += r[i].w; if(i < m - 1 && r[i].w == r[i + 1].w || i && r[i].w == r[i - 1].w) { flag = 1; tag[tn ++] = i; } } } for(int i = 1;i <= n;i ++) { if(getf(i) == i) num ++; } if(num != 1) printf("No MST\n%d",num); else printf("%d\n%s",c,!flag || !check() ? "Yes" : "No"); }