最小生成樹的演算法想必大家都很了解,主要有kruskal和prim。但如果要求次小生成樹(即第二小的生成樹)呢?
一種容易想到的方法是列舉刪除最小生成樹上的邊,再求最小生成樹。用kruskal這種演算法的複雜度為o(n*elog2e),當圖比較稠密時,複雜度接近o(n^3)。
但有一種更簡單的方法:先求最小生成樹t,列舉新增不在t中的邊,則新增後一定會形成環。找到環上邊值第二大的邊(即環中屬於t中的最大邊),把它刪掉,計算當前生成樹的權值,取所有列舉修改的生成樹的最小值,即為次小生成樹。
這種方法在實現時有更簡單的方法:首先求最小生成樹t,然後從每個結點u遍歷最小生成樹t,用乙個二維陣列max[u][v]記錄結點u到結點v的路勁上邊的最大值(即最大邊的值)。然後列舉不在t中的邊(u,v),計算t- max[u][v] + w(u,v)的最小值,即為次小生成樹的權值。顯然,這種方法的時間複雜度為o(n^2 + e)。
可見,第二種演算法將原來的時間複雜度o(n^3)提高到了o(n^2)。
例:判斷生成樹的唯一性,唯一則輸出權值,不唯一輸出not unique!(poj1679)
顯然,可以轉化為求次小生成樹,次小生成樹權值=最小生成樹,則不唯一。
#include #include #include const int inf = 0x7fffffff;
const int max = 10001;
int n,m;
int num;
int p[max];
int max[101][101];
struct edge //原始圖
e[max];
struct tree //最小生成樹
tree[202];
int index[101];
struct node //生成樹的結點
;bool cmp(const edge &a, const edge &b)
void makeset()
}int findset(int x)
void addedge(int from, int to, int w)
int kruscal()
} return edgenum == n-1 ? result : -1;
}void bfs(int p)
} }}void second_mst()
} if(smst == mst)
printf("not unique!\n");
else
printf("%d\n",mst);
}int main()
num = 0;
memset(index,-1,sizeof(index));
second_mst();
} return 0;
}
最小生成樹 次小生成樹
一 最小生成樹 說到生成樹首先要解釋一下樹,樹是乙個聯通的無向無環圖,多棵樹的集合則被稱為森林。因此,樹具有許多性質 1.兩點之間的路徑是唯一的。2.邊數等於點數減一。3.連線任意兩點都會生成乙個環。對於乙個無向聯通圖g的子圖,如果它包含g的所有點,則它被稱為g的生成樹,而各邊權和最小的生成樹則被稱...
次小生成樹
演算法引入 設g v,e,w 是連通的無向圖,t是圖g的一棵最小生成樹 如果有另一棵樹t1,滿足不存在樹t t t1 則稱t1是圖g的次小生成樹 演算法思想 鄰集的概念 由t進行一次可行交換得到的新的生成樹所組成的集合,稱為樹t的鄰集,記為n t 設t是圖g的最小生成樹,如果t1滿足 t1 min,...
次小生成樹
分類 圖論 2013 02 12 15 03 32人閱讀收藏 舉報次小生成樹 在求最小生成樹時,用陣列path i j 來表示mst中i到j最大邊權。求完後,直接列舉所有不在mst中的邊,把它加入到mst中構成一棵新的樹,且該樹有環,此環是由剛加入的邊 i,j 造成的,所以可以通過刪除path i ...