生成树计数问题(SPOJ 104 Highways)

  周冬的《生成树的计数及其应用》论文上讲到过生成树计数的问题。

用到的是一个Kirchhoff矩阵,它是这样定义的:

a、设一个度数矩阵D,当i == j时,Dij = (i这个节点的度数),否则Dij = 0;

b、设一个连通性矩阵A,如果i 和j连通,则Aij等于i到j的边数,否则Aij等于0;

Kirchhoff矩阵C = D - A;

有了Kirchhoff矩阵这个工具,我们可以引入Matrix-Tree定理:
对于一个无向图G,它的生成树个数等于其Kirchhoff矩阵任何一个n-1阶主子式的行列式的绝对值(可以用高斯消元解,线性代数没学好的面壁去。。。-_-!)。
所谓n-1阶主子式,就是对于任意一个r,将C的第r行和第r列同时删去后的新矩阵,用Cr表示。

代码(SPOJ 104 Highways)

View Code
//#pragma comment(linker,"/STACK:327680000,327680000")
#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <cstring>
#include <algorithm>
#include <string>
#include <set>
#include <functional>
#include <numeric>
#include <sstream>
#include <stack>
#include <map>
#include <queue>

#define CL(arr, val) memset(arr, val, sizeof(arr))
#define REP(i, n)for((i) = 0; (i) < (n); ++(i))
#define FOR(i, l, h)for((i) = (l); (i) <= (h); ++(i))
#define FORD(i, h, l)for((i) = (h); (i) >= (l); --(i))
#define L(x)(x) << 1
#define R(x)(x) << 1 | 1
#define MID(l, r)(l + r) >> 1
#define Min(x, y)x < y ? x : y
#define Max(x, y)x < y ? y : x
#define E(x)(1 << (x))
#define iabs(x) (x) < 0 ? -(x) : (x)
#define OUT(x)printf("%I64d\n", x)
#define lowbit(x)(x)&(-x)
#define Read()freopen("data.in", "r", stdin)
#define Write()freopen("data.out", "w", stdout);

const double eps = 1e-8;
typedef long long LL;
const int inf = ~0u>>2;

using namespace std;

const int N = 111;
const int M = 2111;
const int MOD = 31011;

int b[N];

bool zero(double x) {
    return x > -eps && x < eps;
}

double det(double mat[N][N], int n) {
    double mul, res = 1;
    int i, j, k;
    for(i = 0; i < n; ++i)  b[i] = i;
    for(i = 0; i < n; ++i) {
        if(zero(mat[b[i]][i])) {
            for(j = i + 1; j < n; ++j) {
                if(!zero(mat[b[j]][i])) {swap(b[i], b[j]); res *= -1; break;}
            }
        }
        res *= mat[b[i]][i];
        for(j = i + 1; j < n; ++j) {
            if(!zero(mat[b[j]][i])) {
                mul = mat[b[j]][i]/mat[b[i]][i];
                for(k = i; k < n; ++k) {
                    mat[b[j]][k] -= mat[b[i]][k]*mul;
                }
            }
        }
    }
    return res;
}


int D[N][N], A[N][N];
double G[N][N];

int main() {
    //freopen("data.in", "r", stdin);

    int T, i, j;
    int n, m, x, y;
    cin >> T;
    while(T--) {
        scanf("%d%d", &n, &m);
        CL(D, 0);
        CL(A, 0);
        while(m--) {
            scanf("%d%d", &x, &y);
            A[x-1][y-1] = A[y-1][x-1] = 1;
        }
        for(i = 0; i < n; ++i) {
            x = 0;
            for(j = 0; j < n; ++j) {
                if(A[i][j])    {x++;}
            }
            D[i][i] = x;
        }
        for(i = 0; i < n; ++i) {
            for(j = 0; j < n; ++j)  G[i][j] = D[i][j] - A[i][j];
        }
        printf("%.0f\n", det(G, n-1));
    }
    return 0;
}
原文地址:https://www.cnblogs.com/vongang/p/2712839.html