7-14 最小生成樹的唯一性(30 分) 生成樹綜合練習題
阿新 • • 發佈:2018-12-13
題目描述:
7-14 最小生成樹的唯一性(30 分)
給定一個帶權無向圖,如果是連通圖,則至少存在一棵最小生成樹,有時最小生成樹並不唯一。本題就要求你計算最小生成樹的總權重,並且判斷其是否唯一。
輸入格式:
首先第一行給出兩個整數:無向圖中頂點數 N(≤500)和邊數 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
賽後分析:比賽的時候根本沒有看這道題,因為一想到自己生成樹都忘記怎麼寫了就直接扔了這道題,後來補題的時候發現,這算是一道比較綜合的生成樹的題目了,應該學習一下
題目分析:求最小生成樹,並判斷是不是唯一的,可以直接先求出次小生成樹,看看相不相等,如果相等,那麼最小生成樹肯定不唯一啊,同時這道題還要判斷存不存在最小生成樹,用並查集即可判斷。
AcCode:
#include<bits/stdc++.h> using namespace std; const int maxn = 510; typedef long long LL; const int INF = 0x3f3f3f3f; int N, M; bool vis[maxn]; //求最小生成樹的時候用來標記是不是已經走過 bool used[maxn][maxn]; //求次小生成樹的時候用 int Map[maxn][maxn]; //儲存任意兩條邊之間的關係 int dis[maxn]; //儲存邊的距離 int pre[maxn]; //儲存之前的點 int MaxP[maxn][maxn]; //i 到 j 之間最大的距離 int f[maxn]; //並查集求連通個數 int prim() //prim演算法求最小生成樹 { for(int i = 1; i <= N; i++){ dis[i] = Map[i][1]; pre[i] = 1; } dis[1] = 0; vis[1] = true; int ans = 0; for(int i = 1; i < N; i++){ int temp = INF, pos; for(int j = 1; j <= N; j++){ if(!vis[j] && temp > dis[j]){ temp = dis[j], pos = j; } } if(temp == INF) return -1; used[pre[pos]][pos] = used[pos][pre[pos]] = true; ans += dis[pos]; vis[pos] = true; for(int j = 1; j <= N; j++){ if(vis[j] && j != pos) MaxP[pos][j] = MaxP[j][pos] = max(MaxP[j][pre[pos]], dis[pos]); if(!vis[j]){ if(dis[j] > Map[pos][j]) { dis[j] = Map[pos][j]; pre[j] = pos; } } } } return ans; } void init() { for(int i = 1; i <= N; i++) //並查集的初始化 f[i] = i; memset(Map, 0x3f, sizeof(Map)); memset(vis, 0, sizeof(vis)); memset(dis, 0x3f, sizeof(dis)); memset(MaxP, 0, sizeof(MaxP)); return ; } int Find(int x) { if(x == f[x]) return x; else return f[x] = Find(f[x]); } void unit(int a, int b) { int fa = Find(a); int fb = Find(b); if(fa == fb) return ; else { if(fa < fb) f[fb] = fa; else f[fa] = fb; } return ; } int main() { scanf("%d %d", &N, &M); init(); while(M--){ int v1, v2, w; scanf("%d %d %d", &v1, &v2, &w); unit(v1, v2); Map[v1][v2] = Map[v2][v1] = w; } int x = prim(); if(x == -1){ //如果不連通 cout << "No MST" << endl; int sum = 0; for(int i = 1; i <= N; i++){ if(i == Find(i)) sum++;} cout << sum << endl; } else { cout << x << endl; int ans = INF; for(int i = 1; i <= N; i++){ for(int j = 1; j <= N; j++){ if(i != j && !used[i][j]) ans = min(ans, x+Map[i][j]-MaxP[i][j]); } } if(ans == x) cout << "No" << endl; else cout << "Yes" << endl; } return 0; }