题意
给定一个个点完全图,以及一棵树,树上边为关键边,问完全图中恰好含
条关键边的生成树有多少。
题解
对于基尔霍夫矩阵树定理,其具体求解的是,我们一般计算题目取
便是单纯的生成树计数,这里考虑生成函数相关:我们取关键边的
,那么求解后
的系数就表示恰好
条边生成树个数。
我们可以知道我们通过矩阵树定理的行列式会算出一个的多项式,那么我们可以考虑对
不同值进行具体计算,算出
个
,然后可以通过高斯消元求解出多项式系数。
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <vector>
using namespace std;
using LL = long long;
const int MAXN = 1e2 + 5;
const int MOD = 1e9 + 7;
int N;
int mp[MAXN][MAXN];
int A[MAXN][MAXN];
int Guass_Elimination_Det(int n);
int b[MAXN], p[MAXN];
int inv(int a, int p);
int qpow(int x, int n);
int main() {
//
scanf("%d", &N);
for (int i = 1; i < N; i++) {
int x, y;
scanf("%d%d", &x, &y);
mp[x][y] = mp[y][x] = 1;
}
for (int k = 1; k <= N; k++) {
for (int i = 1; i <= N; i++) A[i][i] = 0;
for (int i = 1; i <= N; i++)
for (int j = 1; j <= N; j++) {
if (i == j) continue;
if (mp[i][j])
A[i][j] = MOD - k, A[i][i] += k;
else
A[i][j] = MOD - 1, A[i][i] += 1;
}
b[k] = Guass_Elimination_Det(N - 1);
}
//
for (int i = 1; i <= N; i++) {
A[i][1] = 1;
for (int j = 2; j <= N; j++) A[i][j] = 1LL * i * A[i][j - 1] % MOD;
}
for (int k = 1; k < N; k++)
for (int i = k + 1; i <= N; i++)
while (A[i][k]) {
int tmp = A[k][k] / A[i][k];
for (int j = k; j <= N; j++) {
A[k][j] = (A[k][j] - 1LL * tmp * A[i][j] % MOD + MOD) % MOD;
swap(A[k][j], A[i][j]);
}
b[k] = (b[k] - 1LL * tmp * b[i] % MOD + MOD) % MOD;
swap(b[k], b[i]);
}
for (int i = N; i >= 1; i--) {
p[i] = b[i];
for (int j = i + 1; j <= N; j++)
p[i] = (p[i] - 1LL * p[j] * A[i][j] % MOD + MOD) % MOD;
p[i] = 1LL * inv(A[i][i], MOD) * p[i] % MOD;
}
for (int i = 1; i <= N; i++) printf("%d ", p[i]);
return 0;
}
int Guass_Elimination_Det(int n) {
int res = 1, mark = 1;
for (int k = 1; k <= n; k++) {
if (!A[k][k])
for (int i = k + 1; i <= n; i++)
if (A[i][k]) {
for (int j = k; j <= n; j++) swap(A[k][j], A[i][j]);
mark *= -1;
break;
}
//
for (int i = k + 1; i <= n; i++) {
int tmp = 1LL * A[i][k] * inv(A[k][k], MOD) % MOD;
for (int j = k + 1; j <= n; j++)
A[i][j] = (A[i][j] - 1LL * tmp * A[k][j] % MOD + MOD) % MOD;
A[i][k] = 0;
}
if (!A[k][k]) return 0;
res = 1LL * res * A[k][k] % MOD;
}
if (mark == -1) res = MOD - res;
return res;
}
int qpow(int x, int n) {
int res = 1;
while (n) {
if (n & 1) res = 1LL * res * x % MOD;
x = 1LL * x * x % MOD;
n >>= 1;
}
return res;
}
int inv(int a, int p) {
// cout << a << " " << p << endl;
a %= p;
if (a == 1) return 1;
return p - 1LL * p * inv(p, a) / a;
}