hdu 4305 Lightning

传送门
就是求生成树的个数
在于建图,建立无向图,如果说两点之间有点,就不能建图,否则,两点之间建立边
也就是说点与点之间最多只有一条边,然后最多能构成一个完全图
首先判断两点之间的距离是否满足,然后判断三点是否贡献
最后利用矩阵树定理求解即可

#include <iostream>
#include <cstdio>
#include <cstring>
#define ll long long
using namespace std;
const int N = 305;
const int mod = 10007;
int a[N][N], b[N][N];
ll pow(ll a, ll b, ll p){
    ll ans = 1; a %= p;
    while(b){
        if(b & 1) ans = ans * a % p;
        a = a * a % p;
        b >>= 1;
    }
    return ans;
}
ll det(int a[][N], int n){
    ll ans = 1;
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= n; j++)
            a[i][j] = (a[i][j] % mod + mod) % mod;
    for(int i = 1; i <= n; i++) {
        int r = i;
        for(int j = i; j <= n; j++) if(a[i][j] > a[r][i]) r = i;
        if(r != i) 
            for(int j = 1; j <= n; j++) swap(a[i][j], a[r][j]);
        if(a[i][i] == 0) return 0;
        ll inv = pow(a[i][i], mod - 2, mod);
        for(int j = i + 1; j <= n; j++) {
            ll tmp = a[j][i] * inv % mod;
            for(int k = i; k <= n; k++)
                a[j][k] = (a[j][k] - a[i][k] * tmp % mod + mod) % mod;
        }
        ans = ans * a[i][i] % mod;
    }
    return ans;
}
struct Point{
    int x, y;
    Point(int x = 0, int y = 0):x(x),y(y){};
    Point operator - (const Point &b) const {
        return Point(x - b.x, y - b.y);
    }
    int operator ^ (const Point &b) const {
        return x * b.y - y * b.x;
    }
    int operator * (const Point &b) const {
        return x * b.x + y * b.y;
    }
}p[N];
typedef Point Vector;
bool OnSegment(Point P1, Point P2, Point Q){//Q是否在线段P1P2上
    return ((P1 - Q) ^ (P2 - Q)) == 0 && ((P1 - Q) * (P2 - Q)) <= 0;
}
int dis(Point a, Point b){
    return (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y);
}
void solve(){
    int n, r;
    scanf ("%d%d", &n, &r);  
    for (int i = 1; i <= n; i++)  
        scanf ("%d%d", &p[i].x, &p[i].y);  
    memset (a, 0, sizeof(a));
    memset(b, 0, sizeof(b));  
    for (int i = 1; i <= n; i++) {  
        for (int j = i + 1; j <= n; j++) {  
            if (dis(p[i], p[j]) > r * r) continue;  
            int k = 0;
            for (k = 1; k <= n; k++) {  
                if (k == i || k == j) continue;  
                if (OnSegment(p[i], p[j], p[k])) break;
            }  
            if (k == n + 1) a[i][j] = a[j][i] = 1;  
        }  
    }  
    for (int i = 1; i <= n; i++)  
        for (int j = i + 1; j <= n; j++)  
            if (a[i][j])  
                ++b[i][i], ++b[j][j];  
   	for (int i = 1; i <= n; i++)  
        for (int j = 1; j <= n; j++)
            b[i][j] -= a[i][j]; 
    int ans = det(b, n - 1);
    printf ("%d
", ans ? ans : -1);  
}
int main(){
    int t;
    scanf("%d", &t);
    while(t--) solve();
}
原文地址:https://www.cnblogs.com/Emcikem/p/13453760.html