Problem Description
There are N robots standing on the ground (Don't know why. Don't know how). 

Suddenly the sky turns into gray, and lightning storm comes! Unfortunately, one of the robots is stuck by the lightning!

So it becomes overladen. Once a robot becomes overladen, it will spread lightning to the near one.

The spreading happens when: 
  Robot A is overladen but robot B not.
  The Distance between robot A and robot B is no longer than R.
  No other robots stand in a line between them.
In this condition, robot B becomes overladen.

We assume that no two spreading happens at a same time and no two robots stand at a same position.


The problem is: How many kind of lightning shape if all robots is overladen? The answer can be very large so we output the answer modulo 10007. If some of the robots cannot be overladen, just output -1. 

 
Input
There are several cases.
The first line is an integer T (T < = 20), indicate the test cases.
For each case, the first line contains integer N ( 1 < = N < = 300 ) and R ( 0 < = R < = 20000 ), indicate there stand N robots; following N lines, each contains two integers ( x, y ) ( -10000 < = x, y < = 10000 ), indicate the position of the robot. 
 
Output
One line for each case contains the answer.
 
Sample Input
3
3 2
-1 0
0 1
1 0
3 2
-1 0
0 0
1 0
3 1
-1 0
0 1
1 0
 
Sample Output
3
1
-1

意:

给出n个点的坐标,距离不超过r的点如果中间没有其它点则可以连一条边,最后求生成树的数量,对10007取模。

分析:

Matrix-Tree定理:Kirchhoff矩阵任意n-1阶子矩阵的行列式的绝对值就是无向图的生成树的数量。

Kirchhoff矩阵的定义是度数矩阵-邻接矩阵。

1、G的度数矩阵D[G]:n*n的矩阵,Dii等于Vi的度数,其余为0。
2、G的邻接矩阵A[G]:n*n的矩阵, Vi、Vj之间有边直接相连,则
Aij=1,否则为0。

有了这个定理,我们要只要构造Kirchhoff矩阵,然后计算行列式就行了,注意要取模。

构造矩阵需要判断一下满足距离不超过r的两点之间是否有其它点,直接三层循环用叉积判断ijk是否共线,如果共线k是否在ij之间。

然后是行列式的计算:

是线性代数的知识,先通过初等变换化成 上三角的行列式,主对角线的积就是行列式的值了。

而初等变换的过程,如果是交换两行,行列式要乘上-1,所以记录一下交换了几次,最后根据奇偶来乘-1。我们要用Cii来消去它下面的数。第i行每个数都要除以Cii,这个过程因为我们是取模的,所以要用逆元,于是提前预处理逆元。

(对于这题我有一个疑惑,如果行列式的值是负数,那么生成树的个数就是它的绝对值,答案不应该是这个绝对值再取模吗,但是它的数据却是MOD-绝对值。比如行列式是-3,生成树应该是3,题目的正确答案却是10004)

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define sqr(x) ((x)*(x))
using namespace std;
const int M=;
const int N=;
int inv[M],mat[N][N];
void init(){//求逆元
inv[]=;
for(int i=;i<M;i++)
inv[i]=(M-M/i)*inv[M%i]%M;
}
int det(int c[][N],int n){//求矩阵c的n阶顺序主子式的绝对值
int i,j,k,w=,ans=;
for(i=;i<n;i++)
for(j=;j<n;j++) c[i][j]=(c[i][j]%M+M)%M;
for(i=;i<n;i++){
for(j=i;j<n;j++)//找出第i行起第i列不为0的行
if(c[i][j])break;
if(i!=j)
swap(c[i],c[j]);
ans=ans*c[i][i]%M;
for(j=i+;j<n;j++)//第j行第i列变为0
for(k=n;k>i;k--)//该行每列减去第i列的值*d
c[j][k]=(c[j][k]-c[i][k]*inv[c[i][i]]%M*c[j][i]%M+M)%M;
}
return ans;
}
struct point{
int x,y;
}p[N];
int same(point a,point b,point c){//判断是否共线
return (a.x-c.x)*(b.y-c.y)==(b.x-c.x)*(a.y-c.y)
&&min(a.x,c.x)<=b.x&&max(a.x,c.x)>=b.x
&&min(a.y,c.y)<=b.y&&max(a.y,c.y)>=b.y;
}
int main(){
init();
int t,n,r;
scanf("%d",&t);
while(t--){
memset(mat,,sizeof mat);
scanf("%d%d",&n,&r);
for(int i=;i<n;i++)
scanf("%d%d",&p[i].x,&p[i].y);
for(int i=;i<n;i++)
for(int j=i+;j<n;j++)
if(sqrt(sqr(p[i].x-p[j].x)+sqr(p[i].y-p[j].y))<=r){//距离不大于r
int ok=;
for(int k=;k<n;k++)
if(k!=i&&k!=j&&same(p[i],p[k],p[j]))
ok=;
if(ok){//构造Kirchhoff矩阵
mat[i][j]=mat[j][i]=-;
mat[i][i]++;mat[j][j]++;
}
}
int ans=det(mat,n-);
printf("%d\n",ans?ans:-);
}
}

另外一种求行列式的方法可以不用求逆元,万一mod是非质数就不能用求逆元了,所以这种方法就派上用场了。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define sqr(x) ((x)*(x))
using namespace std;
const int M=;
const int N=;
int mat[N][N];
int det(int c[][N],int n){
int i,j,k,t,ret=;
for(i=;i<n;i++)
for(j=;j<n;j++) c[i][j]%=M;
for(i=; i<n; i++){
for(j=i+; j<n; j++)
while(c[j][i])
{
t=c[i][i]/c[j][i];//类似辗转相除
for(k=i; k<n; k++)
c[i][k]=(c[i][k]-c[j][k]*t)%M;
swap(c[i],c[j]);
ret=-ret;
}
if(c[i][i]==)
return 0L;
ret=ret*c[i][i]%M;
}
return (ret+M)%M;
}
struct point{
int x,y;
}p[N];
int same(point a,point b,point c){
return (a.x-c.x)*(b.y-c.y)==(b.x-c.x)*(a.y-c.y)
&&min(a.x,c.x)<=b.x&&max(a.x,c.x)>=b.x
&&min(a.y,c.y)<=b.y&&max(a.y,c.y)>=b.y;
}
int main(){
int t,n,r;
scanf("%d",&t);
while(t--){
memset(mat,,sizeof mat);
scanf("%d%d",&n,&r);
for(int i=;i<n;i++)
scanf("%d%d",&p[i].x,&p[i].y);
for(int i=;i<n;i++)
for(int j=i+;j<n;j++)
if(sqrt(sqr(p[i].x-p[j].x)+sqr(p[i].y-p[j].y))<=r){
int ok=;
for(int k=;k<n;k++)
if(k!=i&&k!=j&&same(p[i],p[k],p[j]))
ok=;
if(ok){
mat[i][j]=mat[j][i]=-;
mat[i][i]++;mat[j][j]++;
}
}
int ans=det(mat,n-);
printf("%d\n",ans?ans:-);
}
}

  

  

【HDU 4305】Lightning(生成树计数)的更多相关文章

  1. HDU - 4305 - Lightning 生成树计数 + 叉积判断三点共线

    HDU - 4305 题意: 比较裸的一道生成树计数问题,构造Krichhoof矩阵,求解行列式即可.但是这道题还有一个限制,就是给定的坐标中,两点连线中不能有其他的点,否则这两点就不能连接.枚举点, ...

  2. HDU 4305 Lightning(计算几何,判断点在线段上,生成树计数)

    Lightning Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total S ...

  3. HDU 4305 Lightning Matrix Tree定理

    题目链接:https://vjudge.net/problem/HDU-4305 解法:首先是根据两点的距离不大于R,而且中间没有点建立一个图.之后就是求生成树计数了. Matrix-Tree定理(K ...

  4. HDU4305:Lightning(生成树计数+判断点是否在线段上)

    Lightning Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total S ...

  5. kuangbin带你飞 生成树专题 : 次小生成树; 最小树形图;生成树计数

    第一个部分 前4题 次小生成树 算法:首先如果生成了最小生成树,那么这些树上的所有的边都进行标记.标记为树边. 接下来进行枚举,枚举任意一条不在MST上的边,如果加入这条边,那么肯定会在这棵树上形成一 ...

  6. 【BZOJ1002】【FJOI2007】轮状病毒(生成树计数)

    1002: [FJOI2007]轮状病毒 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 1766  Solved: 946[Submit][Status ...

  7. SPOJ 104 HIGH - Highways 生成树计数

    题目链接:https://vjudge.net/problem/SPOJ-HIGH 解法: 生成树计数 1.构造 基尔霍夫矩阵(又叫拉普拉斯矩阵) n阶矩阵 若u.v之间有边相连 C[u][v]=C[ ...

  8. Luogu P5296 [北京省选集训2019]生成树计数

    Luogu P5296 [北京省选集训2019]生成树计数 题目链接 题目大意:给定每条边的边权.一颗生成树的权值为边权和的\(k\)次方.求出所有生成树的权值和. 我们列出答案的式子: 设\(E\) ...

  9. Loj 2320.「清华集训 2017」生成树计数

    Loj 2320.「清华集训 2017」生成树计数 题目描述 在一个 \(s\) 个点的图中,存在 \(s-n\) 条边,使图中形成了 \(n\) 个连通块,第 \(i\) 个连通块中有 \(a_i\ ...

  10. 「UVA10766」Organising the Organisation(生成树计数)

    BUPT 2017 Summer Training (for 16) #6C 题意 n个点,完全图减去m条边,求生成树个数. 题解 注意可能会给重边. 然后就是生成树计数了. 代码 #include ...

随机推荐

  1. 关于maya动力学系统的一些总结

    maya动力学有以下几套系统: 1.刚体.柔体系统 刚体系统的典型节点连接方法如下: 物体的变换节点.形状节点连接rigidBody节点,刚体节点输出力到解算器节点,解算器输出新的变换到变换节点 值得 ...

  2. Centos5.8下编译安装PHP5.4和memcached, phalcon, yaf, apc

    安装GIT 需要先安装gcc-c++ (sudo yum install gcc-c++)sudo yum install gettext-devel expat-devel cpio perl op ...

  3. 在C#中将String转换成Enum:

    一:  在C#中将String转换成Enum: object Enum.Parse(System.Type enumType, string value, bool ignoreCase); 所以,我 ...

  4. windows 10磁盘占用100%解决方案

    可以试试在 控制面板–管理工具–服务– HomeGroup Listener和HomeGroup Provider禁用. (这2项服务是家庭组共享用的,一般我们也不会去共享什么的.) 效果:我的磁盘是 ...

  5. BZOJ 1066 【SCOI2007】 蜥蜴

    Description 在一个r行c列的网格地图中有一些高度不同的石柱,一些石柱上站着一些蜥蜴,你的任务是让尽量多的蜥蜴逃到边界外. 每行每列中相邻石柱的距离为$1$,蜥蜴的跳跃距离是d,即蜥蜴可以跳 ...

  6. 重构Web Api程序(Api Controller和Entity)

    Insus.NET较习惯做法,是在程序完成之后,抽一些少时间对写好的代码重新审视.比如这些天写的Web Api的程序来说,发现有很多值得重构代码. 开发ASP.NET MVC程序,与数据相关有关联的一 ...

  7. 15个nosql数据库

    1.MongoDB 介绍 MongoDB是一个基于分布式文件存储的数据库.由C++语言编写.主要解决的是海量数据的访问效率问题,为WEB应用提供可扩展的高性能数据存储解决方案.当数据量达到50GB以上 ...

  8. java中wait/notify机制

    通常,多线程之间需要协调工作.例如,浏览器的一个显示图片的线程displayThread想要执行显示图片的任务,必须等待下载线程 downloadThread将该图片下载完毕.如果图片还没有下载完,d ...

  9. ssh生成key不交互

    ssh-keygen -t rsa -f ~/.ssh/id_rsa -P ""   首次执行不交互 第二次再次执行会让输入y

  10. CSS3 动画效果带来的bug

    css3 动画效果比如transition:all 2s linear;这种用来计算及时的物体坐标的话会带来一定的问题 比如把一个DIV从A点移动到B点.JS为DIV.style.left=B; 但是 ...