HDU--4305(生成树计数)
2015-09-07 22:23:26
【传送门】
题意:平面上300个点,如果两点之间距离<=R,且两点形成的线段上没有另外的点,那么两点之间有一条无向边。问生成树的方案数。
思路:暴力n^2建图,关于判断两点形成线段上是否有其他点,比如判断 k 点知否在 i ,j 之间,首先看斜率是否相等,不能直接求斜率,而应该转化为乘式;再判断 dis(i,k)+dis(k,j)是否等于 dis(i,j),如果斜率一样且距离相等那么 k 点在 i,j 之间。
建完图后就是Matrix-Tree定理的运用了,注意取模。
#include <cstdio> #include <ctime> #include <cstring> #include <cstdlib> #include <cmath> #include <vector> #include <map> #include <set> #include <stack> #include <queue> #include <string> #include <iostream> #include <algorithm> using namespace std; #define getmid(l,r) ((l) + ((r) - (l)) / 2) #define MP(a,b) make_pair(a,b) #define PB push_back typedef long long ll; typedef pair<int,int> pii; const double eps = 1e-8; const int INF = (1 << 30) - 1; const int MAXN = 310; const int mod = 10007; int T; int N,R; int X[MAXN],Y[MAXN]; double dis[MAXN][MAXN]; int G[MAXN][MAXN]; int vis[MAXN]; int sign(double x){ if(fabs(x) < eps) return 0; if(x < 0) return -1; return 1; } double Dis(int a,int b){ return sqrt(1.0 * (X[a] - X[b]) * (X[a] - X[b]) + 1.0 * (Y[a] - Y[b]) * (Y[a] - Y[b])); } void Dfs(int p){ vis[p] = 1; for(int i = 1; i <= N; ++i) if(G[p][i] && !vis[i]) Dfs(i); } int Det(int n){ int A[MAXN][MAXN]; for(int i = 1; i <= n; ++i) for(int j = 1; j <= n; ++j) A[i][j] = G[i][j]; int res = 1; for(int i = 1; i <= n; ++i){ for(int j = i + 1; j <= n; ++j){ while(A[j][i]){ int t = A[i][i] / A[j][i]; for(int k = i; k <= n; ++k) A[i][k] = (A[i][k] - A[j][k] * t) % mod; for(int k = i; k <= n; ++k) swap(A[i][k],A[j][k]); res = -res; //行列式换行,值取反 } } if(!A[i][i]) return 0; res = res * A[i][i] % mod; } return (res + mod) % mod; } int main(){ scanf("%d",&T); while(T--){ scanf("%d%d",&N,&R); for(int i = 1; i <= N; ++i){ scanf("%d%d",X + i,Y + i); for(int j = 1; j < i; ++j){ dis[i][j] = dis[j][i] = Dis(i,j); } } memset(G,0,sizeof(G)); for(int i = 1; i <= N; ++i){ for(int j = i + 1; j <= N; ++j) if(!(dis[i][j] > R)){ bool can = true; for(int k = 1; k <= N; ++k) if(k != i && k != j){ if((Y[j] - Y[i]) * (X[k] - X[i]) == (Y[k] - Y[i]) * (X[j] - X[i]) && sign(dis[i][k] + dis[k][j] - dis[i][j]) == 0){ can = false; break; } } if(can){ G[i][i]++; G[j][j]++; G[i][j] = G[j][i] = -1; } } } memset(vis,0,sizeof(vis)); Dfs(1); bool flag = true; for(int i = 1; i <= N; ++i) if(!vis[i]) flag = false; if(!flag){ printf("-1\n"); continue; } int ans = Det(N - 1); printf("%d\n",ans); } return 0; }