题意:
求最小生成树和次小生成树的总权值。
思路:
第一种做法,适用于规模较小的时候,prim算法进行的时候维护在树中两点之间路径中边的最大值,复杂度O(n^2),枚举边O(m),总复杂度O(n^2);
第二种做法,倍增求lca,预处理复杂度O(nlog(n)),替换的时候log(n),总复杂度为O(mlog(n))。
代码:
1 #include <stdio.h> 2 #include <string.h> 3 #include <algorithm> 4 using namespace std; 5 6 const int maxn = 105; 7 const int inf = 0x3f3f3f3f; 8 9 int mp[maxn][maxn]; 10 bool vis[maxn]; 11 bool used[maxn][maxn]; 12 int d[maxn]; 13 int path[maxn][maxn]; 14 int pre[maxn]; 15 16 int prim(int n) 17 { 18 memset(path,0,sizeof(path)); 19 memset(vis,0,sizeof(vis)); 20 memset(used,0,sizeof(used)); 21 22 vis[1] = 1; 23 d[1] = 0; 24 25 int ans = 0; 26 27 for (int i = 2;i <= n;i++) 28 { 29 pre[i] = 1; 30 d[i]= mp[1][i]; 31 } 32 33 for (int i = 0;i < n - 1;i++) 34 { 35 int x = -1,dis = inf; 36 37 for (int j = 1;j <= n;j++) 38 { 39 if (!vis[j] && d[j] < dis) 40 { 41 dis = d[j]; 42 x = j; 43 } 44 } 45 46 vis[x] = 1; 47 used[x][pre[x]] = used[pre[x]][x] = 1; 48 49 ans += dis; 50 51 for (int j = 1;j <= n;j++) 52 { 53 if (vis[j] && j != x) path[j][x] = path[x][j] = max(dis,path[j][pre[x]]); 54 55 if (!vis[j] && mp[x][j] < d[j]) 56 { 57 d[j] = mp[x][j]; 58 pre[j] = x; 59 } 60 } 61 } 62 63 return ans; 64 } 65 66 int main() 67 { 68 int t; 69 70 scanf("%d",&t); 71 72 while (t--) 73 { 74 int n,m; 75 76 scanf("%d%d",&n,&m); 77 78 memset(mp,inf,sizeof(mp)); 79 80 for (int i = 0;i < m;i++) 81 { 82 int a,b,c; 83 84 scanf("%d%d%d",&a,&b,&c); 85 86 mp[a][b] = mp[b][a] = min(mp[a][b],c); 87 } 88 89 int ans1 = prim(n); 90 91 int ans2 = inf; 92 93 for (int i = 1;i <= n;i++) 94 { 95 for (int j = i + 1;j <= n;j++) 96 { 97 if (used[i][j]) continue; 98 99 ans2 = min(ans2,ans1 - path[i][j] + mp[i][j]); 100 } 101 } 102 103 printf("%d %d ",ans1,ans2); 104 } 105 106 return 0; 107 }