Problem Description
There are N robots standing on the ground (Don't know why. Don't know how).
Suddenly the sky turns into gray, and lightning storm comes! Unfortunately, one of the robots is stuck by the lightning!
So it becomes overladen. Once a robot becomes overladen, it will spread lightning to the near one.
The spreading happens when:
Robot A is overladen but robot B not.
The Distance between robot A and robot B is no longer than R.
No other robots stand in a line between them.
In this condition, robot B becomes overladen.
We assume that no two spreading happens at a same time and no two robots stand at a same position.
The problem is: How many kind of lightning shape if all robots is overladen? The answer can be very large so we output the answer modulo 10007. If some of the robots cannot be overladen, just output -1.
Input
There are several cases.
The first line is an integer T (T < = 20), indicate the test cases.
For each case, the first line contains integer N ( 1 < = N < = 300 ) and R ( 0 < = R < = 20000 ), indicate there stand N robots; following N lines, each contains two integers ( x, y ) ( -10000 < = x, y < = 10000 ), indicate the position of the robot.
Output
One line for each case contains the answer.
Sample Input
3
3 2
-1 0
0 1
1 0
3 2
-1 0
0 0
1 0
3 1
-1 0
0 1
1 0
Sample Output
首先是根据两点的距离不大于R,而且中间没有点建立一个图,之后就是求生成树计数了。
Matrix-Tree定理(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 <iostream>
#include <string.h>
#include <math.h>
#include <stdio.h>
using namespace std;
#define mod 10007
int N,R;
struct Point //点的定义
{
int x,y;
Point(int x=0,int y=0):x(x),y(y){}
}P[301];
Point operator - (Point A,Point B)
{
return Point(A.x-B.x,A.y-B.y);
}
double Cross(Point A,Point B)//叉积
{
return A.x*B.y-A.y*B.x;
}
int dcmp(double x)//精度
{
if(fabs(x)<1e-0)return 0;
else return x<0?-1:1;
}
double Dot(Point A,Point B)//点积
{
return A.x*B.x+A.y*B.y;
}
double Distance(Point A,Point B)
{
return (A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y);
}
bool onSegment(Point p,Point a1,Point a2)//判断点是否在线段上
{
return dcmp(Cross(a1-p,a2-p))==0&&dcmp(Dot(a1-p,a2-p))<0;
}
bool check(int k1,int k2)//判断两点之间的距离小于等于R且中间没有点阻隔
{
if(Distance(P[k1],P[k2])>R*R)return false;
for(int i=0;i<N;i++)
if(i!=k1&&i!=k2)
if(onSegment(P[i],P[k1],P[k2]))
return false;
return true;
}
long long INV(long long a,long long m)//求a*x=1(mod m)的逆元x
{
if(a==1)return 1;
return INV(m%a,m)*(m-m/a)%m;
}
struct Matrix
{
int mat[301][301];
Matrix(){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=(mod-res)%mod;
break;
}
if(mat[i][i]==0)
{
res=-1;
break;
}
for(int j=i+1;j<n;j++)
{
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;
}
};
int main()
{
int T;
cin>>T;
while(T--)
{
int g[301][301];
memset(g,0,sizeof(g));
cin>>N>>R;
for(int i=0;i<N;i++)
scanf("%d%d",&P[i].x,&P[i].y);
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;
for(int i=0;i<N;i++)
for(int j=0;j<N;j++)
if(i!=j&&g[i][j]==1)
{
ret.mat[i][j]=-1;
ret.mat[i][i]++;
}
cout<<ret.det(N-1)<<endl;
}
return 0;
}