【bzoj2467】[中山市选2010]生成树 矩阵树定理
题目描述
有一种图形叫做五角形圈。一个五角形圈的中心有1个由n个顶点和n条边组成的圈。在中心的这个n边圈的每一条边同时也是某一个五角形的一条边,一共有n个不同的五角形。这些五角形只在五角形圈的中心的圈上有公共的顶点。如图0所示是一个4-五角形圈。
现在给定一个n五角形圈,你的任务就是求出n五角形圈的不同生成树的数目。还记得什么是图的生成树吗?一个图的生成树是保留原图的所有顶点以及顶点的数目减去一这么多条边,从而生成的一棵树。
注意:在给定的n五角形圈中所有顶点均视为不同的顶点。
输入
输入包含多组测试数据。第一行包含一个正整数T,表示测试数据数目。每组测试数据包含一个整数n( 2<=N<=100),代表你需要求解的五角形圈中心的边数。
输出
对每一组测试数据,输出一行包含一个整数x,表示n五角形圈的生成树数目模2007之后的结果。
样例输入
1
2
样例输出
40
题解
矩阵树定理
看到无向图生成树个数,直接裸上矩阵树定理就好了(好像本题还有组合数学法)。
需要注意的是由于2007不是质数,因此需要辗转相除。
另外当n=2时由于某些特殊原因需要特判。
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int mod = 2007; int a[410][410]; int main() { int T; scanf("%d" , &T); while(T -- ) { memset(a , 0 , sizeof(a)); int n , i , j , k , t , ans = 1 , d = 0; scanf("%d" , &n) , n <<= 2; if(n == 8) { puts("40"); continue; } for(i = 1 ; i <= n ; i ++ ) { a[i][(i + 1) % n] = a[(i + 1) % n][i] = -1 , a[i][i] = 2; if(i % 4 == 1) a[i][i] = 4 , a[i][(i + 4) % n] = a[(i + 4) % n][i] = -1; } for(i = 1 ; i < n ; i ++ ) { for(j = i ; j < n ; j ++ ) if(a[j][i]) break; if(j == n) continue; if(j != i) { d ^= 1; for(k = i ; k < n ; k ++ ) swap(a[i][k] , a[j][k]); } for(j = i + 1 ; j < n ; j ++ ) { while(a[j][i]) { t = a[j][i] / a[i][i]; for(k = i ; k < n ; k ++ ) a[j][k] = (a[j][k] - a[i][k] * t % mod + mod) % mod; if(!a[j][i]) break; d ^= 1; for(k = i ; k < n ; k ++ ) swap(a[i][k] , a[j][k]); } } } for(i = 1 ; i < n ; i ++ ) ans = ans * a[i][i] % mod; if(d) ans = (mod - ans) % mod; printf("%d\n" , ans); } return 0; }