题目传送门:POJ-1679 The Unique MST
题目大意:
题目给了一个无向图,判断该图的最小生成树是否唯一。
分析:
要求出无向图的次小生成树,若次小生成树的权值和最小生成树权值一样,则最小生成树不唯一,否则唯一。
求次小生成树:首先需要求出最小生成树,然后暴力枚举非最小生成树的边,将边加入最小生成树中,
此时会形成一个环,将环中权值最大的边删除(不是新加入的边),得到另一个生成树,枚举完成后,
取所有新生成树中最小的值,若该值和最小生成树值相等,则最小生成树不唯一,否则唯一。
需要数组:
Max[i][j]:i -->j路径中权值最大的边
pre[i]: i的直接前驱结点
used[i][j]:判断(i,j)这条边是否在最小生成树中
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int MAX=109; const int INF=0x3f3f3f3f; int t,n,m,a,b,val; int mst_num,smst_num; int map[MAX][MAX]; int dist[MAX]; int vis[MAX]; int used[MAX][MAX]; //记录(i,j)是否为最小生成树中的边 int pre[MAX]; //记录i结点的直接前驱 int Max[MAX][MAX]; //记录i-->j路径中权值最大的边 int prim() { for(int i = 1;i <= n;i++) //初始化 dist[i] = INF; memset(vis,false,sizeof(vis)); memset(used,false,sizeof(used)); memset(pre,0,sizeof(pre)); memset(Max,0,sizeof(MAX)); dist[1] = 0; int ans = 0; for(int i = 1;i <= n;i++) { int min = INF,pos; for(int j = 1;j <= n;j++) { if(!vis[j]&&dist[j] < min) { min = dist[j]; pos = j; } } ans += min; vis[pos] = true; used[pos][pre[pos]] = used[pre[pos]][pos] = true; //标记新加入最小生成树的边 for(int j = 1;j <= n;j++) { if(vis[j]&&i!=j)Max[j][pos] = max(min,Max[pre[pos]][j]); //更新pos-->到生成树上点的路径最大边权 if(!vis[j]&&dist[j] > map[pos][j]) { dist[j] = map[pos][j]; pre[j] = pos; //更新前驱 } } } return ans; } int smst() { int Min=INF; for(int i = 1;i <= n;i++) for(int j = i+1;j <= n;j++) //枚举非MST的边,加入生成树形成环,减去该环上权值最大的边 { if(!used[i][j]&&map[a][b]!=INF) Min = min(Min,mst_num + map[i][j] - Max[i][j]); } return Min; } int main() { scanf("%d",&t); while(t--) { scanf("%d%d",&n,&m); for(int i = 1;i <= n;i++) //初始化 for(int j = 1;j <= n;j++) map[i][j] = INF; while(m--) { scanf("%d%d%d",&a,&b,&val); map[a][b] = map[b][a] = min(map[a][b],val); } mst_num=prim(); smst_num=smst(); if(mst_num == smst_num)printf("Not Unique!\n"); else printf("%d\n",mst_num); } return 0; }