hdu 4305 Lightning - 矩陣樹Matrix-tree + 計算幾何判斷三點共線
阿新 • • 發佈:2020-08-07
傳送門
就是求生成樹的個數
在於建圖,建立無向圖,如果說兩點之間有點,就不能建圖,否則,兩點之間建立邊
也就是說點與點之間最多隻有一條邊,然後最多能構成一個完全圖
首先判斷兩點之間的距離是否滿足,然後判斷三點是否貢獻
最後利用矩陣樹定理求解即可
#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\n", ans ? ans : -1); } int main(){ int t; scanf("%d", &t); while(t--) solve(); }