1. 程式人生 > >uva10766生成樹計數

uva10766生成樹計數

als mes art 算子 技術分享 math 個數 main mat

此類題是給定一個無向圖,求所有生成樹的個數,生成樹計數要用到Matrix-Tree定理(Kirchhoff矩陣-樹定理)

G的度數矩陣D[G]是一個n*n的矩陣,並且滿足:當i≠j時,dij=0;當i=j時,dij等於vi的度數

G的鄰接矩陣A[G]也是一個n*n的矩陣, 並且滿足:如果vi、vj之間有邊直接相連,則aij=1,否則為0

我們定義G的Kirchhoff矩陣(也稱為拉普拉斯算子)C[G]為C[G]=D[G]-A[G],則Matrix-Tree定理可以描述為:G的所有不同的生成樹的個數等於其Kirchhoff矩陣C[G]任何一個n-1階主子式的行列式的絕對值。所謂n-1階主子式,就是對於r(1≤r≤n),將C[G]的第r行、第r列同時去掉後得到的新矩陣,用Cr[G]表示。

證明:http://blog.csdn.net/creationaugust/article/details/46389553

因為基爾霍夫矩陣i!=j處要麽是0,要麽是-1,這樣處理起來就很方便

技術分享
#include<map>
#include<set>
#include<ctime>
#include<cmath>
#include<queue>
#include<stack>
#include<vector>
#include<cstdio>
#include<iomanip>
#include
<cstdlib> #include<cstring> #include<iostream> #include<algorithm> #define pi acos(-1) #define ll long long #define mod 1000000007 #define ls l,m,rt<<1 #define rs m+1,r,rt<<1|1 #define MIN(a,b) a<b ? a:b using namespace std; const double g=10.0,eps=1e-9; const int N=50+10
,maxn=500000+10,inf=0x3f3f3f3f; ll D[N]; ll A[N][N]; ll solve(int n) { ll ans=1; for(int i=1;i<n;i++) { for(int j=i+1;j<n;j++) { while(A[j][i]){ ll t=A[i][i]/A[j][i]; for(int k=i;k<n;k++) A[i][k]-=(A[j][k]*t); for(int k=i;k<n;k++) swap(A[i][k],A[j][k]); ans=-ans; } } if(A[i][i]==0)return 0; ans*=A[i][i]; } if(ans<0)ans=-ans; return ans; } int main() { ios::sync_with_stdio(false); cin.tie(0); int n,k,m; while(cin>>n>>m>>k){ for(int i=1;i<=n;i++) { D[i]=A[i][i]=0; for(int j=i+1;j<=n;j++) A[i][j]=A[j][i]=1; } while(m--){ int a,b; cin>>a>>b; A[a][b]=A[b][a]=0; } for(int i=1;i<=n;i++) for(int j=1+i;j<=n;j++) if(A[i][j]) D[i]++,D[j]++; for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { if(i==j)A[i][j]=D[i]; else A[i][j]=-A[i][j]; } } /* for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) cout<<A[i][j]<<" "; cout<<endl; }*/ ll res=solve(n); cout<<res<<endl; } return 0; }
View Code

uva10766生成樹計數