最小生成樹計數(MST) kruskal&矩陣定理
阿新 • • 發佈:2018-12-23
參考的有這位大佬的部落格:https://blog.csdn.net/clover_hxy/article/details/69397184
最小生成樹的兩個性質:
(1)不同的最小生成樹中,每種權值的邊出現的個數是確定的
(2)不同的生成樹中,某一種權值的邊連線完成後,形成的聯通塊狀態是一樣的
那麼我們其實可以把每種權值的處理看成是分開的好幾步,然後根據乘法原理,將每一步得到的結果相乘。
通過舉例子進行說明,下圖中s1,s2,s3表示已經處理好的3個連通塊,虛線表示一組同權值的邊。加入這組邊後s1,s2,s3可以連通。
將已經計算好的連通塊縮成一個點,那麼就變成了一個獨立的圖的生成樹問題,可以用矩陣樹定理求解。
code:
#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<algorithm> #include<vector> #include<set> #include<cmath> #include<map> using namespace std; #define N 1005 int n, m; int p[N]; int ex[105]; int ts[N], tt[N]; int tans = 0; int exist[N]; int C[12][12]; struct edge { int v1, v2; int w; }E[N]; bool cmp(edge x, edge y) { return x.w < y.w; } void init() { for (int i = 1; i <= n; i++) { p[i] = i; exist[i] = 0; } } int find(int x) { if (x != p[x]) { p[x] = find(p[x]); } return p[x]; } void buM(int l, int r) { init(); for (int i = 0; i < m; i++) { if ((i<l || i>r)&&ts[i]) { int x = find(E[i].v1); int y = find(E[i].v2); if (x != y) { if (x > y) swap(x, y); p[y] = x; } } } } int matrixtheorem(int t) { int ht = 1; if (t == 3) return abs(C[2][2] * C[3][3] - (C[2][3] * C[3][2])); t = t - 1; int mu1 = 1;int mu2 = 1;int sum1 = 0;int M = 0; for (int i = 0; i <= t-ht; i++) { mu1 = 1; mu2 = 1; for (int j = 1; j <= t; j++) { int h = (j + i) > t ? (j + i - t) : j + i; mu1 *= C[j + 1][h + 1]; mu2 *= C[j + 1][t + 2 - h]; } sum1 += (mu1 - mu2); } return abs(sum1); } int main() { memset(ts, 0, sizeof(ts)); scanf("%d%d", &n, &m); for (int i = 0; i < m; i++) { scanf("%d%d%d", &E[i].v1, &E[i].v2, &E[i].w); } sort(E, E + m, cmp); init(); for (int i = 0; i < m; i++) { int x = find(E[i].v1); int y = find(E[i].v2); if (x != y) { ts[i] = 1; if (x > y)swap(x, y); p[y] = x; } } int rex = E[0].w; int ansx = 0, tans = 0; for (int i = 0; i < m; i++) { if (E[i].w == rex) { ansx++; } else { rex = E[i].w; tt[tans++] = ansx; i--; ansx = 0; } } tt[tans++] = ansx; int l, r; l = 0; r = 0; E[m].w = -1; int ttt = tans; for (int i = 0; i < ttt; i++) { r = l + tt[i] - 1; int sums = 0; for (int j = l; j <= r; j++) { sums += ts[j]; } if (l == r || sums <= 0) { l = r + 1; ex[tans++] = 1; continue; } memset(C, 0, sizeof(C)); buM(l, r); int res[N];int t = 0;int flag = 0; for (int j = l; j <= r; j++) { int x = find(E[j].v1), y = find(E[j].v2); if (x != y) { flag = 1; if (!exist[x]) { exist[x] = 1; res[x] = ++t; } if (!exist[y]) { exist[y] = 1; res[y] = ++t; } //cout << res[x] << " " << res[y] << endl; C[res[x]][res[y]]--; C[res[y]][res[x]]--; C[res[x]][res[x]]++; C[res[y]][res[y]]++; } } if (!flag) { l = r + 1; ex[tans++] = 1; continue; } /*for (int j = 1; j <= t; j++) { for(int k=1;k<=t;k++) cout << C[j][k] << " "; cout << endl; }*/ if (t == 2) ex[tans++] = C[2][2]; else ex[tans++] = matrixtheorem(t); l = r + 1; } int mu = 1; for (int i = 0; i < tans; i++) { //cout << ex[i] << endl; if (ex[i] == 0) continue; mu *= ex[i]; } cout << mu << endl; return 0; }