传送门
题意:N个机器人在那站着,一天打雷霹到一个机器人,那么距离他小于R以内的机器人都会被霹到,但是三点共线的情况只能传染最近的那个,问最后闪电击中形成的形状有多少种,也就是求无向图生成树个数。
求生成树个数问题最好的方法是Matrix-Tree定理。
Matrix-Tree定理:
一,
对于无向图A表示其邻接矩阵,B表示其度数矩阵,Kirchhoff矩阵H=B-A
简单的来说可以这么表示,
当 i!=j 时且A[i][j]==1, H[i][j]=-1,
当i==j时,H[i][j]=i的度数。举例。
那么其Kirchhoff矩阵就是右边的矩阵。
那么该图生成树个数=H的任意一个代数余子式。
二,
对于有向图的Krichhoff矩阵 H[i][j]有所不同;
当i!=j H[i][j]=顶点 j到顶点i的路径条数
当i==j H[]i[j]=顶点i的入度
而其生成树个数与根节点有关,以i点为根的生成树个数=去除i行i列的代数余子式。(因为矩阵一定是V*V的方阵,i点位于i行j列,i==j,所以称为i行i列)
所以求有向图的生成树个数要枚举所有点(根)。
三,
本题呢,肯定是无向图啦,枚举所有点求出每个点之间的距离,把距离小于R的且两点之间不含有其他点的 两个点连接形成一条边,得到邻接矩阵A,那么Krichhoff矩阵唾手可得。
然后求任意一个代数余子式即可。代数余子式用模板求一下就行了。
模板:
LL inv(LL a,LL m)///逆元
{
if(a==1)return 1;
return inv(m%a,m)*(m-m/a)%m;
}
struct Matrix
{
LL mat[MAXN][MAXN];
void init()
{
memset(mat,0,sizeof(mat));
}
LL det(int n)
{
for(int i=0; i<n; i++)
for(int j=0; j<n; j++)
mat[i][j]=(mat[i][j]%MOD+MOD)%MOD;
LL res=1;
for(int i=0; i<n; i++)
{
for(int j=i; j<n; j++)
{
if(mat[i][j]!=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=0;///不存在,行列式为0
break;
}
for(int j=i+1; j<n; j++)
{
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;
}
};
Matrix ret;
ret.init();
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
if(i!=j&&g[i][j])
{
ret.mat[i][j]=-1;
res.mat[i][i]++;
}
}
}
本题代码:
#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
typedef long long LL;
using namespace std;
const int MOD=10007;
const int MAXN=305;
int R;
struct node
{
int x,y;
}d[305];
int N;
int dis(int i,int j)
{
return (d[i].x-d[j].x)*(d[i].x-d[j].x)+(d[i].y-d[j].y)*(d[i].y-d[j].y);
}
int ok(int i,int j)
{
int temp=dis(i,j);
if(temp>R*R)
return 0;
for(int k=0;k<N;k++)
{
if(k!=i&&k!=j)
{
if(dis(i,k)<temp
&&dis(k,j)<temp&&
(d[i].x-d[k].x)*(d[j].y-d[k].y)==(d[j].x-d[k].x)*(d[i].y-d[k].y))///叉积==0
return 0;
}
}
return 1;
}
LL inv(LL a,LL m)
{
if(a==1)return 1;
return inv(m%a,m)*(m-m/a)%m;
}
struct Matrix
{
int mat[MAXN][MAXN];
void init()
{
memset(mat,0,sizeof(mat));
}
int det(int n)
{
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[i][j]!=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))%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 G[MAXN][MAXN];
int main()
{
int T,n;
cin>>T;
while(T--)
{
scanf("%d%d",&n,&R);
N=n;
for(int i=0;i<n;i++)
scanf("%d%d",&d[i].x,&d[i].y);
Matrix Mat;
Mat.init();
memset(G,0,sizeof(G));
for(int i=0;i<n;i++)
{
for(int j=i+1;j<n;j++)
{
if(ok(i,j))
G[i][j]=G[j][i]=1;
}
}
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
if(G[i][j]&&i!=j)
{
Mat.mat[i][j]=-1;
Mat.mat[i][i]++;
}
}
}
cout<<Mat.det(n-1)<<endl;
}
return 0;
}