题意:
有N个点在二维平面上...两点间若距离不大于R并且构成的线段中没有其他的点..则可以连一条边..现在问..这个图有多少个生成树
题解:
觉得这题好屌...一些计算几的知识+神奇的矩阵+高斯消元(同时要求逆元)...
先构边...按照题目的要求..ok的就有边...构边就直接构造Matrix Tree吧...而Matrix Tree构造的矩阵意思是: 对角线上为每个点的度..非对角线上为两点间连着边的个数的相反数..由于本题没有重边.那么就是有边则为-1..没边则为0...构造出矩阵..去掉任意一个十字..剩下的行列式之合就是该图的生成树的个数..好神奇..不懂如何证明...直接拿来用了...最后就是要求一个矩阵的行列式...方法有很多种...一般都是用高斯消元...高斯消元的方法是每次让一列只剩下一个数..其他数约掉...最后矩阵转化为一个上三角..对角线乘积则为矩阵的行列式...手算的时候一般会出现几分之几...程序如果也用double来写最后又回到int..可能会产生一些精度问题..但高斯消元是可以让每一步都是整数的.如本题..由于最后的答案要mod一个数...当要做除法时..直接用逆元就好..若没有取模运算..那么就先对所有行做lcm...然后再消...
Program:
#include<iostream> #include<stdio.h> #include<string.h> #include<cmath> #include<queue> #include<stack> #include<set> #include<time.h> #include<map> #include<algorithm> #define ll long long #define eps 1e-5 #define oo 10007 #define pi acos(-1.0) #define MAXN 305 using namespace std; struct node { int x,y; node () {} node ( int x , int y ) : x(x) , y(y) {} }p[MAXN]; typedef node Vector; Vector operator - ( node a , node b ) { return Vector ( a.x - b.x , a.y - b.y ); } int Dot ( Vector a , Vector b ) { return a.x*b.x + a.y * b.y; } int dis(node p1,node p2) { return (p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y); } int Cross (Vector a , Vector b ) { return a.x*b.y - a.y*b.x; } bool InLine(node p1,node p2,node p3) { return Cross ( p1 - p2 , p3 - p2 ) == 0 && Dot ( p1 - p2 , p3 - p2 ) < 0; } int C[MAXN][MAXN]; void exgcd(int a,int b,int &x,int &y) { if(b==0) { x=1,y=0; return; } exgcd(b,a%b,x,y); int t; t=x,x=y,y=t-a/b*y; return; } int det(int n)//计算n阶行列式的绝对值%mod { int ans=1,flag=1;//flag行列交换的次数..为奇数则要*-1 int i,j,k; for(i=0;i<n;i++) { if(C[i][i]==0) { for(j=i+1;j<n;j++) if(C[j][i])break; if(j==n) return 0;//某列的值全是0的ans=0; flag=!flag; for(int k=i;k<n;k++) swap(C[i][k],C[j][k]);//i和j行交换 } ans=ans*C[i][i]%oo;//对角线相乘 int x,y; exgcd(C[i][i],oo,x,y);//x为逆元.若没有取模运算那就需要LCM再来化 for(k=i+1;k<n;k++) C[i][k]=C[i][k]*x%oo; for(int j=i+1;j<n;j++) for(int k=i+1;k<n;k++) { C[j][k]=(C[j][k]-C[j][i]*C[i][k])%oo; C[j][k]=(C[j][k]+oo)%oo; } } ans=(ans%oo+oo)%oo; if(flag) return ans; else return oo-ans; } int main() { int T,N,R,i,j,x; scanf("%d",&T); while (T--) { scanf("%d%d",&N,&R); R*=R; for (i=0;i<N;i++) scanf("%d%d",&p[i].x,&p[i].y); memset(C,0,sizeof(C)); for (i=0;i<N;i++) for (j=i+1;j<N;j++) if (dis(p[i],p[j])<=R) { for (x=0;x<N;x++) if (InLine(p[i],p[x],p[j])) goto A; C[i][i]++,C[j][j]++; C[i][j]=C[j][i]=-1; A: ; } x=det(N-1); if (!x) x=-1; printf("%d\n",x); } return 0; }