1. 程式人生 > >最小生成樹計數(MST) kruskal&矩陣定理

最小生成樹計數(MST) kruskal&矩陣定理

參考的有這位大佬的部落格: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;
}