1. 程式人生 > >【中山市選2010】【BZOJ2467】生成樹

【中山市選2010】【BZOJ2467】生成樹

online 中心 什麽是 var cti spl scrip scanf load

Description

有一種圖形叫做五角形圈。一個五角形圈的中心有1個由n個頂點和n條邊組成的圈。

在中心的這個n邊圈的每一條邊同一時候也是某一個五角形的一條邊,一共同擁有n個不同的五角形。這些五角形僅僅在五角形圈的中心的圈上有公共的頂點。如圖0所看到的是一個4-五角形圈。
技術分享

如今給定一個n五角形圈。你的任務就是求出n五角形圈的不同生成樹的數目。還記得什麽是圖的生成樹嗎?一個圖的生成樹是保留原圖的全部頂點以及頂點的數目減去一這麽多條邊,從而生成的一棵樹。
註意:在給定的n五角形圈中全部頂點均視為不同的頂點。


Input

輸入包括多組測試數據。

第一行包括一個正整數T,表示測試數據數目。每組測試數據包括一個整數n( 2<=N<=100),代表你須要求解的五角形圈中心的邊數。

Output

對每一組測試數據,輸出一行包括一個整數x。表示n五角形圈的生成樹數目模2007之後的結果。
Sample Input

1

2

Sample Output

40
HINT

Source

直接Matrix-tree定理就好了
也能夠用組合數學/DP來做
關於組合數學能夠看PoPoQQQ的blog
果然還是矩陣樹好想…

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define MAXN 1010
#define P 2007 using namespace std; int A[MAXN][MAXN],D[MAXN][MAXN],C[MAXN][MAXN]; int n,top; int T; int calc(int size) { for (int i=1;i<size;i++) for (int j=1;j<size;j++) C[i][j]=(C[i][j]+P)%P; int ret=1; for (int i=1;i<size;i++) { for (int j=i+1;j<size;j++) { int
a=C[i][i],b=C[j][i]; while (b) { int temp=a/b;a%=b;swap(a,b); for (int k=i;k<size;k++) C[i][k]=(C[i][k]-temp*C[j][k])%P; for (int k=i;k<size;k++) swap(C[i][k],C[j][k]); ret=-ret; } } if (!C[i][i]) return 0; ret=ret*C[i][i]%P; } return (ret+P)%P; } int main() { scanf("%d",&T); while (T--) { memset(A,0,sizeof(A));memset(D,0,sizeof(D)); scanf("%d",&n); top=n; for (int i=1;i<=n;i++) { int u=i,v=i+1>n?1:i+1; A[u][top+1]++;A[top+1][u]++;D[u][u]++;D[top+1][top+1]++; A[top+1][top+2]++;A[top+2][top+1]++;D[top+1][top+1]++;D[top+2][top+2]++; A[top+2][top+3]++;A[top+3][top+2]++;D[top+2][top+2]++;D[top+3][top+3]++; A[top+3][v]++;A[v][top+3]++;D[top+3][top+3]++;D[v][v]++; top+=3; A[u][v]++;A[v][u]++;D[u][u]++;D[v][v]++; } for (int i=1;i<=top;i++) for (int j=1;j<=top;j++) C[i][j]=D[i][j]-A[i][j]; cout<<calc(top)<<endl; } }

【中山市選2010】【BZOJ2467】生成樹