HDU 4305 Lightning Matrix Tree定理
题目链接:https://vjudge.net/problem/HDU-4305
解法:首先是根据两点的距离不大于R,而且中间没有点建立一个图。之后就是求生成树计数了。
Matrix-Tree定理(Kirchhoff矩阵-树定理)。Matrix-Tree定理是解决生成树计数问题最有力的武器之一。它首先于1847年被Kirchhoff证明。在介绍定理之前,我们首先明确几个概念:
1、G的度数矩阵D[G]是一个n*n的矩阵,并且满足:当i≠j时,dij=0;当i=j时,dij等于vi的度数。
2、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]表示。
#include <bits/stdc++.h> using namespace std; struct Point{ int x,y; Point(int _x = 0, int _y = 0){ x = _x; y = _y; } Point operator -(const Point &b) const{ return Point(x-b.x,y-b.y); } int operator ^(const Point &b) const{ return x*b.y-y*b.x; } void input(){ scanf("%d %d", &x,&y); } }; struct Line{ Point s,e; Line(){} Line(Point _s, Point _e){ s = _s; e = _e; } }; bool onSeg(Point P, Line L){ return ((L.s-P)^(L.e-P))==0 && (P.x-L.s.x)*(P.x-L.e.x)<=0 && (P.y-L.s.y)*(P.y-L.e.y)<=0; } int getDis(Point a, Point b){ return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y); } const int mod = 10007; long long inv(long long a, long long m){ if(a==1) return 1; return inv(m%a,m)*(m-m/a)%m; } struct Matrix{ int mat[330][330]; void init(){ memset(mat,0,sizeof(mat)); } int det(int n){ for(int i=0; i<n; i++) for(int j=0; j<n; j++) mat[i][j] = (mat[i][j]%mod+mod)%mod; int res=1; for(int i=0; i<n; i++){ for(int j=i; j<n; j++){ if(mat[j][i]!=0){ for(int k=i; k<n; k++){ swap(mat[i][k], mat[j][k]); } if(i != j) res = (-res+mod)%mod; break; } } if(mat[i][i] == 0){ res = -1; break; } for(int j=i+1; j<n; j++){ int mul = (mat[j][i]*inv(mat[i][i],mod))%mod; for(int k=i; k<n; k++){ mat[j][k] = (mat[j][k]-(mat[i][k]*mul)%mod+mod)%mod; } } res = (res * mat[i][i])%mod; } return res; } }; int g[330][330]; Point p[330]; int n, R; bool check(int k1, int k2){ if(getDis(p[k1], p[k2]) > R*R) return false; for(int i=0; i<n; i++){ if(i!=k1&&i!=k2){ if(onSeg(p[i],Line(p[k1],p[k2]))){ return false; } } } return true; } int main() { int T; scanf("%d", &T); while(T--) { scanf("%d %d", &n,&R); for(int i=0; i<n; i++) p[i].input(); memset(g, 0, sizeof(g)); for(int i=0; i<n; i++) for(int j=i+1; j<n; j++) if(check(i,j)) g[i][j] = g[j][i] = 1; Matrix ret; ret.init(); for(int i=0; i<n; i++) for(int j=0; j<n; j++) if(i!=j&&g[i][j]){ ret.mat[i][j]=-1; ret.mat[i][i]++; } printf("%d\n", ret.det(n-1)); } return 0; }