UVA10766(Organising the Organisation)生成樹計數-Matrix-Tree定理
阿新 • • 發佈:2019-02-11
/* *題目地址: *http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1707; * *題目大意: *Jimmy在公司裡負責人員的分級工作,他最近遇到了一點小麻煩; *為了提高公司工作的效率,董事會決定對所有的員工重新分級; *即除了一個總經理例外,其他所有的員工有且只有一個直接領導; *由於員工直接的人際關係,可能出現a和b都不願意讓對方成為自己直接領導的情況; *公司裡的n位員工1~n編號,並且董事會已經決定讓標號為k的員工擔任總經理; *Jimmy的任務就是一共有多少種不同的員工分級方案; * *演算法思想: *如果a和b直接沒有矛盾,就在他們之間連一條邊; *則最後得到的員工之間的關係圖就是原圖的一顆生成樹; *雖然規定了生成樹的根,但是因為無向圖生成樹的個數與根無關; *所以只需要直接利用Matrix-Tree定理計算原圖的生成樹的個數即可; * *Matrix-Tree定理: *G的所有不同的生成樹的個數等於其Kirchhoff矩陣C[G]任何一個n-1階主子式的行列式的絕對值; *n-1階主子式就是對於r(1≤r≤n),將C[G]的第r行,第r列同時去掉後得到的新矩陣,用Cr[G]表示; **/ #include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; const int N=55; typedef long long LL; int D[N][N]; LL C[N][N];//Kirchhoff矩陣 LL Det(LL a[][N],int n)//生成樹計數:Matrix-Tree定理 { LL ret=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[i][k]-a[j][k]*t); for(int k=i; k<n; k++) swap(a[i][k],a[j][k]); ret=-ret; } if(a[i][i]==0) return 0; ret=ret*a[i][i]; } if(ret<0) ret=-ret; return ret; } int main() { //freopen("C:\\Users\\Administrator\\Desktop\\kd.txt","r",stdin); int n,m,k; while(~scanf("%d%d%d",&n,&m,&k)) { memset(C,0,sizeof(C)); memset(D,0,sizeof(D)); int u,v; while(m--) { scanf("%d%d",&u,&v); u--; v--; D[u][v]=D[v][u]=1; } for(int i=0; i<n; i++) { int u=0; for(int j=0; j<n; j++) { if(i!=j&&!D[i][j]) { u++; C[i][j]=-1; } } C[i][i]=u; } LL res=Det(C,n); printf("%lld\n",res); } return 0; }