題意:
有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 305using 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;}