1. 程式人生 > >POJ-1679 The Unique MST(次小生成樹)

POJ-1679 The Unique MST(次小生成樹)

map 最大的 org 另一個 cstring can mst clu pre

題目傳送門: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])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 = 1;j <= n;j++) //枚舉非MST的邊,加入生成樹形成環,減去該環上權值最大的邊 { if(!used[i][j]) 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] = val; } mst_num=prim(); smst_num=smst(); if(mst_num == smst_num)printf("Not Unique!\n"); else printf("%d\n",mst_num); } return 0; }

POJ-1679 The Unique MST(次小生成樹)