题意:平面上有N<300个点。每个两个点如果距离小于R且之间没有共线的另一个点,则这两点之间有一条边。求这个图的生成树的个数mod 10007。
思路:首先建图,判断任意两点间有无其他点,没有的话连一条边,剩下的就是统计生成树的数量。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<vector>
#include<map>
#include<queue>
#include<stack>
#include<string>
#include<map>
#include<set>
#include<ctime>
#define eps 1e-6
#define LL long long
#define pii pair<int, int>
//#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
const int MAXN = 350;
const int MOD = 10007;
//const int INF = 0x3f3f3f3f;
int n, r;
int inv[11000];
int pow_mod(int a, int p, int n) {
if(p == 0) return 1;
LL ans = pow_mod(a, p/2, n);
ans = ans * ans % n;
if(p%2 == 1) ans = ans * a % n;
return ans;
}
void init() {
inv[0] = 1;
for(int i = 1; i < MOD; i++) inv[i] = pow_mod(i, MOD-2, MOD);
}
struct Point {
int x, y;
Point(int x=0, int y=0) : x(x), y(y) {}
} p[MAXN];
typedef Point Vector;
Vector operator + (Vector A, Vector B) { return Vector(A.x+B.x, A.y+B.y); }
Vector operator - (Point A, Point B) { return Vector(A.x-B.x, A.y-B.y); }
Vector operator * (Vector A, int p) { return Vector(A.x*p, A.y*p); }
int operator * (Vector A, Vector B) { return A.x*B.y - A.y*B.x; }
Vector operator / (Vector A, int p) { return Vector(A.x/p, A.y/p); }
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 get_dis(int i, int j) {
return (p[i].x-p[j].x)*(p[i].x-p[j].x) + (p[i].y-p[j].y)*(p[i].y-p[j].y);
}
bool check(int a, int b) {
if(get_dis(a, b) > r*r) return false;
Line tmp = Line(p[a], p[b]);
for(int k = 0; k < n; k++) if(k!=a && k!=b) {
if(onSeg(p[k], tmp)) return false;
}
return true;
}
struct Matrix {
int a[MAXN][MAXN];
Matrix() {
memset(a, 0, sizeof(a));
}
void clear() {
memset(a, 0, sizeof(a));
}
Matrix operator + (const Matrix &b) const {
Matrix tmp;
for(int i = 0; i < n; i++)
for(int j = 0; j < n; j++)
tmp.a[i][j] = a[i][j] + b.a[i][j];
return tmp;
}
Matrix operator * (const Matrix& b) const {
Matrix tmp;
tmp.clear();
for(int i = 0; i < n; i++)
for(int j = 0; j < n; j++)
for(int k = 0; k < n; k++) tmp.a[i][j] += a[i][k]*b.a[k][j];
return tmp;
}
Matrix operator ^ (int k) {
Matrix ans, tmp = *this;
while(k) {
if(k&1) ans = ans * tmp;
k >>= 1;
tmp = tmp * tmp;
}
return ans;
}
int det(int n)//求行列式的值模上MOD,需要使用逆元
{
for(int i = 0;i < n;i++)
for(int j = 0;j < n;j++)
a[i][j] = (a[i][j]%MOD+MOD)%MOD;
int res = 1;
for(int i = 0;i < n;i++)
{
for(int j = i;j < n;j++)
if(a[j][i]!=0)
{
for(int k = i;k < n;k++)
swap(a[i][k],a[j][k]);
if(i != j)
res = (-res+MOD)%MOD;
break;
}
if(a[i][i] == 0)
{
res = -1;//不存在(也就是行列式值为0)
break;
}
for(int j = i+1;j < n;j++)
{
//int mut = (a[j][i]*INV[a[i][i]])%MOD;//打表逆元
int mut = (a[j][i]*inv[a[i][i]])%MOD;
for(int k = i;k < n;k++)
a[j][k] = (a[j][k]-(a[i][k]*mut)%MOD+MOD)%MOD;
}
res = (res * a[i][i])%MOD;
}
return res;
}
};
Matrix C;
int main() {
//freopen("input.txt", "r", stdin);
int T; cin >> T;
init();
while(T--) {
cin >> n >> r;
C.clear();
for(int i = 0, u, v; i < n; i++) {
scanf("%d%d", &u, &v);
p[i] = Point(u, v);
}
for(int i = 0; i < n; i++) {
for(int j = i+1; j < n; j++) {
if(check(i, j)) {
C.a[i][j]--;
C.a[j][i]--;
C.a[i][i]++;
C.a[j][j]++;
}
}
}
cout << C.det(n-1) << endl;
}
return 0;
}