Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1099 Accepted Submission(s): 363
首先是根据两点的距离不大于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 <stdio.h> #include <algorithm> #include <iostream> #include <string.h> #include <vector> #include <queue> #include <map> #include <set> #include <list> #include <string> #include <math.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 sqdis(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; int INV[MOD]; //求ax = 1( mod m) 的x值,就是逆元(0<a<m) 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)//求行列式的值模上MOD,需要使用逆元 { 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;//不存在(也就是行列式值为0) break; } for(int j = i+1;j < n;j++) { //int mut = (mat[j][i]*INV[mat[i][i]])%MOD;//打表逆元 int mut = (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]*mut)%MOD+MOD)%MOD; } res = (res * mat[i][i])%MOD; } return res; } }; Point p[330]; int n,R; bool check(int k1,int k2)//判断两点的距离小于等于R,而且中间没有点阻隔 { if(sqdis(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 g[330][330]; int main() { //预处理逆元 for(int i = 1;i < MOD;i++) INV[i] = inv(i,MOD); 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; }