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

Lightning

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1099    Accepted Submission(s): 363


Problem Description
There are N robots standing on the ground (Don't know why. Don't know how). 
HDU 4305 Lightning(计算几何,判断点在线段上,生成树计数)

Suddenly the sky turns into gray, and lightning storm comes! Unfortunately, one of the robots is stuck by the lightning!
HDU 4305 Lightning(计算几何,判断点在线段上,生成树计数)

So it becomes overladen. Once a robot becomes overladen, it will spread lightning to the near one.
HDU 4305 Lightning(计算几何,判断点在线段上,生成树计数)


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. 

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

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
 

 

Author
BUPT
 

 

Source
 

 

Recommend
zhuyuanchen520
 

 

首先是根据两点的距离不大于R,而且中间没有点建立一个图。

之后就是求生成树计数了。

 

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 <stdio.h>

#include <algorithm>

#include <iostream>

#include <string.h>

#include <vector>

#include <queue>

#include <map>

#include <set>

#include <list>

#include <string>

#include <math.h>

using namespace std;



struct Point

{

    int x,y;

    Point(int _x = 0,int _y = 0)

    {

        x = _x,y = _y;

    }

    Point operator - (const Point &b)const

    {

        return Point(x-b.x,y-b.y);

    }

    int operator ^(const Point &b)const

    {

        return x*b.y - y*b.x;

    }

    void input()

    {

        scanf("%d%d",&x,&y);

    }

};

struct Line

{

    Point s,e;

    Line(){}

    Line(Point _s,Point _e)

    {

        s = _s;

        e = _e;

    }

};

bool onSeg(Point P,Line L)

{

    return

    ((L.s-P)^(L.e-P)) == 0 &&

    (P.x-L.s.x)*(P.x-L.e.x) <= 0 &&

    (P.y-L.s.y)*(P.y-L.e.y) <= 0;

}

int sqdis(Point a,Point b)

{

    return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);

}



const int MOD = 10007;

int INV[MOD];

//求ax = 1( mod m) 的x值,就是逆元(0<a<m)

long long inv(long long a,long long m)

{

    if(a == 1)return 1;

    return inv(m%a,m)*(m-m/a)%m;

}

struct Matrix

{

    int mat[330][330];

    void init()

    {

        memset(mat,0,sizeof(mat));

    }

    int det(int n)//求行列式的值模上MOD,需要使用逆元

    {

        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[j][i]!=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;//打表逆元

                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;

    }

};



Point p[330];

int n,R;

bool check(int k1,int k2)//判断两点的距离小于等于R,而且中间没有点阻隔

{

    if(sqdis(p[k1],p[k2]) > R*R)return false;

    for(int i = 0;i < n;i++)

        if(i!=k1 && i!=k2)

            if(onSeg(p[i],Line(p[k1],p[k2])))

                return false;

    return true;

}

int g[330][330];

int main()

{

    //预处理逆元

    for(int i = 1;i < MOD;i++)

        INV[i] = inv(i,MOD);

    int T;

    scanf("%d",&T);

    while(T--)

    {

        scanf("%d%d",&n,&R);

        for(int i = 0;i < n;i++)

            p[i].input();

        memset(g,0,sizeof(g));

        for(int i = 0;i < n;i++)

            for(int j = i+1;j <n;j++)

                if(check(i,j))

                    g[i][j] = g[j][i] = 1;

        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;

                    ret.mat[i][i]++;

                }

        printf("%d\n",ret.det(n-1));

    }

    return 0;

}

 

 

 

 

你可能感兴趣的:(HDU)