hdu 4305 生成树计数问题
Lightning
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1457 Accepted Submission(s): 469

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.
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.
Matrix-Tree定理(Kirchhoff矩阵-树定理)。Matrix-Tree定理是解决生成树计数问题最有力的武器之一。它首先于1847年被Kirchhoff证明。在介绍定理之前,我们首先明确几个概念:
1、G的度数矩阵D[G]是一个n*n的矩阵,并且满足:当i≠j时,dij=0;当i=j时,dij等于vi的度数。
2、G的邻接矩阵A[G]也是一个n*n的矩阵, 并且满足:如果vi、vj之间有边直接相连,则aij=1,否则为0。
我们定义G的Kirchhoff矩阵(也称为拉普拉斯算子)C[G]为C[G]=D[G]-A[G],则Matrix-Tree定理可以描述为:G的所有不同的生成树的个数等于其Kirchhoff矩阵C[G]任何一个n-1阶主子式的行列式的绝对值。所谓n-1阶主子式,就是对于r(1≤r≤n),将C[G]的第r行、第r列同时去掉后得到的新矩阵,用Cr[G]表示。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std; typedef _int64 LL;
const int maxn=;
const int MOD=;
int n,R;
int g[maxn][maxn],d[maxn][maxn],mat[maxn][maxn];//邻接矩阵,度数矩阵,D-G矩阵 struct Point
{
int x,y;
Point(int x=,int y=):x(x),y(y){}
}p[maxn];
typedef Point Vector;
Vector operator -(Vector A,Vector B){return Vector(A.x-B.x,A.y-B.y);}
int Dot(Vector A,Vector B){ return A.x*B.x+A.y*B.y;}//点积
int Cross(Vector A,Vector B){ return A.x*B.y-A.y*B.x;}//叉积
int Length2(Vector A){return Dot(A,A);}//向量模的平方
bool OnSegment(Point p,Point a1,Point a2)//点是否在直线上(不包括端点)
{
return Cross(a1-p,a2-p)== && Dot(a1-p,a2-p)<;
} LL Extended_Euclid(LL a,LL b,LL &x,LL &y)
{
LL d,t;
if(b==){x=;y=;return a;}
d=Extended_Euclid(b,a%b,x,y);
t=x;x=y;y=t-a/b*y;
return d;
}
LL inv(LL a,LL n)//计算模n下a的逆,若不存在逆返回-1
{
LL d,x,y;
d=Extended_Euclid(a,n,x,y);
return d==?(x+n)%n:-;
}
int Det(int n)//求行列式的值模上MOD,需要使用逆元
{
int i,j,k,ret=;
for(i = ;i < n;i++)
for(j = ;j < n;j++)
mat[i][j] = (mat[i][j]%MOD+MOD)%MOD;
for(i = ;i < n;i++)
{
for(j = i;j < n;j++)
if(mat[j][i]!=)
{
for(k = i;k < n;k++) swap(mat[i][k],mat[j][k]);
if(i != j) ret = (-ret+MOD)%MOD;
break;
}
if(mat[i][i]==)
{
ret=;break;
}
for(j=i+;j<n;j++)
{
int mut=(mat[j][i]*inv(mat[i][i],MOD))%MOD;
for(k=i;k<n;k++)
mat[j][k]=(mat[j][k]-(mat[i][k]*mut)%MOD+MOD)%MOD;
}
ret=(ret*mat[i][i])%MOD;
}
return ret;
} void build_graph()
{
memset(g,,sizeof(g));
memset(d,,sizeof(d));
int i,j,k;
for(i=;i<n;i++)
{
for(j=i+;j<n;j++)
{
if(Length2(p[j]-p[i])>R*R) continue;
bool flag=;
for(k=;k<n;k++)
if(OnSegment(p[k],p[i],p[j])){flag=;break;}
if(flag){ g[i][j]=g[j][i]=;d[i][i]++;d[j][j]++;}
}
}
} void get_DGMatrix()
{
for(int i=;i<n;i++)
for(int j=;j<n;j++)
mat[i][j]=d[i][j]-g[i][j];
} int main()
{
int t,i;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&R);
for(i=;i<n;i++) scanf("%d%d",&p[i].x,&p[i].y);
build_graph();
get_DGMatrix();
int ans=Det(n-);
printf("%d\n",ans?ans:-);
}
return ;
}
hdu 4305 生成树计数问题的更多相关文章
- HDU - 4305 - Lightning 生成树计数 + 叉积判断三点共线
HDU - 4305 题意: 比较裸的一道生成树计数问题,构造Krichhoof矩阵,求解行列式即可.但是这道题还有一个限制,就是给定的坐标中,两点连线中不能有其他的点,否则这两点就不能连接.枚举点, ...
- HDU 4305 Lightning(计算几何,判断点在线段上,生成树计数)
Lightning Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total S ...
- HDU 4305 Lightning Matrix Tree定理
题目链接:https://vjudge.net/problem/HDU-4305 解法:首先是根据两点的距离不大于R,而且中间没有点建立一个图.之后就是求生成树计数了. Matrix-Tree定理(K ...
- 【HDU 4305】Lightning(生成树计数)
Problem Description There are N robots standing on the ground (Don't know why. Don't know how). Sudd ...
- HDU 4786 生成树 并查集+极大极小值 黑白边 确定选择白边的数量
题意: 给定一个无向图 n 个点 m条无向边 u v val val == 1 表示边(u, v) 为白边 问能否找到n个点的生成树, 使得白边数为斐波那契数 思路: 并查集求图是否连通( 是否存在生 ...
- HDU 4832(DP+计数问题)
HDU 4832 Chess 思路:把行列的情况分别dp求出来,然后枚举行用几行,竖用几行.然后相乘累加起来就是答案 代码: #include <stdio.h> #include < ...
- 使用Matrix-tree与它的行列式来解决生成树计数问题
我又把Matrix写错啦 这东西讲课的时候竟然一笔带过了,淦 好吧这东西我不会证 那我们来愉快的看结论吧 啦啦啦 预备工作 你有一个 $ n $ 个点的图 比如说 5 /|\ / | \ 2--1-- ...
- HDU 1010生成树
求起点到终点的最短权值和
- hdu 4305 概率dp
/* 题目大意:有n个房间由n-1个隧道连接起来,从1号房间开始, 每个节点i都有三种可能: 1.被杀死,回到节点1,概率为ki; 2.找到出口,离开迷宫,概率ei; 3.与它相连的有m个房间,到任意 ...
随机推荐
- CPP-基础:C/C++数组名与指针的区别
2005-08-23 08:36 来源:天极网 作者:宋宝华 责任编辑:方舟·yesky 引言 指针是C/C++语言的特色,而数组名与指针有太多的相似,甚至很多时候,数组名可以作为指针使用.于是乎,很 ...
- python之道13
看代码分析结果 func_list = [] for i in range(10): func_list.append(lambda :i) v1 = func_list[0]() v2 = func ...
- axure的基本使用方法(侧边导航栏的制作)
1.创建一个动态面板control 2.在home中创建动态面板homepage和movepage并且完成布局 3.给home添加移动事件 4.给按钮添加点击事件 5.大功告成
- VIM 编辑器 -使用详解记录
1.什么是 vim? Vim是从 vi 发展出来的一个文本编辑器.代码补完.编译及错误跳转等方便编程的功能特别丰富,在程序员中被广泛使用.简单的来说, vi 是老式的字处理器,不过功能已经很齐全了,但 ...
- Linux网络配置指令
版权声明:本文为博主原创文章,未经博主允许不得转载. 原文地址: https://www.cnblogs.com/poterliu/p/6686799.html 重启网卡service network ...
- CentOS 7 忘记root密码解决方法
CentOS 7 root密码的重置方式和CentOS 6完全不一样,CentOS 7与之前的版本6变化还是比较大的,以进入单用户模式修改root密码为例: 1.重启机器,进入grub菜单的时候按e ...
- 如何用纯 CSS 和 D3 创作一只扭动的蠕虫
效果预览 在线演示 按下右侧的"点击预览"按钮可以在当前页面预览,点击链接可以全屏预览. https://codepen.io/comehope/pen/QBQJMg 可交互视频 ...
- JAVA基础篇—文件上传下载
/index.jsp <%@ page language="java" contentType="text/html; charset=UTF-8" pa ...
- viewController备注
1.按结构可以对iOS的所有ViewController分成两类: 1).主要用于展示内容的ViewController,这种ViewController主要用于为用户展示内容,并与用户交互,如UIT ...
- kettle-单表增量同步
目标:利于kettle实现单表增量同步,以时间为判断条件 背景:源表:db1.q1 (2w条数据) 目标表:db2.q2(0条数据) 表结构: CREATE TABLE `q1` ( `ID` bi ...