Organising the Organisation (生成树计数)

做这道题,需要三个预备知识:

Kirchhoff 矩阵

先构造两个矩阵

D N × N 度数矩阵D:是一个N×N的矩阵,其中
D [ i ] [ j ] = 0 ( i j ) D [ i ] [ i ] = i D[i][j]=0(i≠j),D[i][i]=i号点的度数

A N × N 邻接矩阵A:是一个N×N的矩阵,其中
A [ i ] [ i ] = 0 , A [ i ] [ j ] = A [ j ] [ i ] = i , j A[i][i]=0,A[i][j]=A[j][i]=i,j之间的边数

K i r c h h o f f K = D A Kirchhoff矩阵K=D−A

举个例子,对于如下的无向图,三个矩阵分别为:(图片来源于网络)
在这里插入图片描述

行列式det(K)及其求法(高斯消元)

百度百科 高斯消元

Matrix−Tree 定理

对于一个无向图G,它的生成树个数等于其Kirchhoff矩阵任何一个n-1阶主子式的行列式的绝对值。

AC code
/*
Organising the Organisation
UVA - 10766
https://vjudge.net/problem/UVA-10766
生成树计数
Matrix−Tree定理:
对于一个无向图G,
它的生成树个数等于其
Kirchhoff矩阵任何一个n-1阶主子式的行列式的绝对值

	度数矩阵D:是一个N×N的矩阵,其中
	D[i][j]=0(i≠j),D[i][i]=i号点的度数
	邻接矩阵A:是一个N×N的矩阵,其中
	A[i][i]=0,A[i][j]=A[j][i]=i,j之间的边数
	Kirchhoff矩阵K=D−A

	然后高斯消元优化为O(n3)
*/
#include <bits/stdc++.h>
using namespace std;
#define ll long long
ll A[60][60];//邻接矩阵
ll K[60][60];//Kirchhoff矩阵
ll det(int n){
  ll ans=1;
  for(ll i=1;i<=n;i++){
    for(ll j=i+1;j<=n;j++){
      while(K[j][i]){
        ll t=K[i][i]/K[j][i];
        for(ll k=i;k<=n;k++){
          K[i][k]-=K[j][k]*t;
          swap(K[i][k],K[j][k]);
        }
        ans=-ans;
      }
    }
    if(K[i][i]==0) return 0;
    ans=ans*K[i][i];
  }
  return ans;
}
int main(){
  int n,m,k;
  while(~scanf("%d %d %d", &n, &m, &k)){
    memset(A,0,sizeof A);
    memset(K,0,sizeof K);
    for(int i=1;i<=m;i++){
      int x,y;
      scanf("%d %d", &x, &y);
      A[x][y]=A[y][x]=1;
    }
    for(int i=1;i<=n;i++){
      for(int j=1;j<=n;j++){
        if(i!=j&&!A[i][j]){
          K[i][i]++;
          K[i][j]--;
        }
      }
    }
    printf("%lld\n", det(n-1));
  }
  return 0;
}


发布了70 篇原创文章 · 获赞 22 · 访问量 6476

猜你喜欢

转载自blog.csdn.net/weixin_44410512/article/details/104225229