uva10766生成樹計數
阿新 • • 發佈:2017-07-10
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> #includeView Code<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; }
uva10766生成樹計數