HDU 4305 Lightning (生成图计数+判断点在线段上)

题意:根据两点的距离不大于R,而且中间没有点建立一个图。求生成树计数。

题解:生成图计数+判断点在线段上
oi-wiki索引:Kirchhoff 矩阵树定理

在这里插入图片描述
则无向图G的生成树个数 = Kirchhoff 矩阵L 的 n-1 阶主子式的行列式的绝对值。

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<queue>
#include<stack>
#include<cmath>
#include<vector>
#include<fstream>
#include<set>
#include<map>
#include<sstream>
#include<iomanip>
#define ll long long
using namespace std;
const int MOD = 10007;
int INV[MOD];
const double eps = 1e-8;
const double inf = 1e20;
const double pi = acos(-1.0);
const int maxp = 1010;
//Compares a double to zero
int sgn(double x) {
    
    
    if (fabs(x) < eps) return 0;
    if (x < 0) return -1;
    else return 1;
}
//square of a double
inline double sqr(double x) {
    
     return x * x; }

//POINT
struct Point {
    
    
    double x, y;
    Point() {
    
    }
    Point(double _x, double _y) {
    
    
        x = _x;
        y = _y;
    }
    Point operator -(const Point& b)const {
    
    
        return Point(x - b.x, y - b.y);
    }
    //叉积
    double operator ^(const Point& b)const {
    
    
        return x * b.y - y * b.x;
    }
    //点积
    double operator *(const Point& b)const {
    
    
        return x * b.x + y * b.y;
    }
    Point operator *(const double& k)const {
    
    
        return Point(x * k, y * k);
    }
};

//LINE
struct Line {
    
    
    Point s, e;
    Line() {
    
    }
    Line(Point _s, Point _e) {
    
    
        s = _s;
        e = _e;
    }
    // 点在线段上的判断
    bool pointonseg(Point p) {
    
    
        return sgn((p - s) ^ (e - s)) == 0 && sgn((p - s) * (p - e)) <= 0;
    }
};

//求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;
    }
};
int ccw(int x1, int y1, int x2, int y2, int x3, int y3) {
    
    
    int v = (x2 - x1) * (y3 - y1) - (x3 - x1) * (y2 - y1);
    if (v == 0) return 0;
    return 1;
}
int t, n, r, x[333], y[333], g[333][333];
int ck(int i, int j) {
    
    
    if ((x[i] - x[j]) * (x[i] - x[j]) + (y[i] - y[j]) * (y[i] - y[j]) > r * r) return 0;
    for (int k = 0; k < n; k++) {
    
    
        if (k == i || k == j) continue;
        Line l = Line(Point(x[i], y[i]), Point(x[j], y[j]));
        if (l.pointonseg(Point(x[k], y[k]))) return 0;
    }
    return 1;
}
int main() {
    
    
    for (int i = 1; i < MOD; i++) INV[i] = inv(i, MOD);
    scanf("%d", &t);
    while (t--) {
    
    
        memset(g, 0, sizeof(g));
        scanf("%d%d", &n, &r);
        for (int i = 0; i < n; i++) scanf("%d%d", &x[i], &y[i]);
        for (int i = 0; i < n; i++) {
    
    
            for (int j = i + 1; j < n; j++) {
    
    
                if (!ck(i, j)) continue;
                g[i][j] = g[j][i] = 1;
            }
        }
        Matrix ma;
        ma.init();
        for (int i = 0; i < n; i++)
            for (int j = 0; j < n; j++)
                if (i != j && g[i][j]) {
    
    
                    ma.mat[i][j] = -1;
                    ma.mat[i][i]++;
                }
        printf("%d\n", ma.det(n - 1));
    }
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_43680965/article/details/107827865