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. Zygote进程【3】——SystemServer的诞生

    在ZygoteInit的main()方法中做了几件大事,其中一件便是启动Systemserver进程,代码如下: @/frameworks/base/core/Java/com/Android/int ...

  2. Hash链表

    <?php /* +------------------------------------------------------------------------------ | dateti ...

  3. node基础01:简要介绍

    1.node vs php 优点 性能高(机制问题) 开发效率高(省了不少优化的事) 应用范围广(可以开发桌面系统,electron框架) 缺点 新,人少 中间件少 IDE不完善 2.node的劣势和 ...

  4. druid 数据源 使用属性文件的一个坑

    直接上代码: <bean id="propertiesFactoryBean" class="org.springframework.beans.factory.c ...

  5. React Native开发技术周报1

    (一).资讯 1.React Native 0.21版本发布,最新版本功能特点,修复的Bug可以看一下已翻译 重要:如果升级 Android 项目到这个版本一定要读! 我们简化了 Android 应用 ...

  6. express:webpack dev-server中如何将对后端的http请求转到https的后端服务器中?

    在上一篇文章(Webpack系列:在Webpack+Vue开发中如何调用tomcat的后端服务器的接口?)我们介绍了如何将对于webpack-dev-server的数据请求转发到后端服务器上,这在大部 ...

  7. 2015-2016-2 《Java程序设计》 学生博客及Git@OSC 链接

    2015-2016-2 <Java程序设计> 学生博客及Git@OSC 链接 博客 1451 20145101王闰开 20145102周正一 20145103冯文华 20145104张家明 ...

  8. Theano2.1.14-基础知识之理解为了速度和正确性的内存别名

    来自:http://deeplearning.net/software/theano/tutorial/aliasing.html Understanding Memory Aliasing for ...

  9. 如何在 apache 中设置缓存有效时间

    今天学习了下如何在 apache 中设置缓存时间,记之以备忘. 在 http 报文头中,与缓存时间有关的两个字段是 Expires 以及 Cache-Control 中的 max-age,Expire ...

  10. Scala入门之控制结构

    package com.dtspark.scala.basics /** * Scala中的基本控制结构有顺序.条件和循环三种方式,这个其它的JVM语言是一致的,但是Scala也有一些高级的流程控制结 ...