hdu 4305 Lightning 高斯消元 计算几何

【BestCoder Round #2 来了!】7月27号19:00~21:00(赛前30分钟停止注册比赛)

Lightning

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


Problem Description
There are N robots standing on the ground (Don't know why. Don't know how).
hdu 4305 Lightning 高斯消元 计算几何_第1张图片
Suddenly the sky turns into gray, and lightning storm comes! Unfortunately, one of the robots is stuck by the lightning!
hdu 4305 Lightning 高斯消元 计算几何_第2张图片
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.

hdu 4305 Lightning 高斯消元 计算几何_第3张图片
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



这道题题意:


有很多机器人,机器人可能被闪电打中,被电到的机器人可以传导电到半径为R的其他机器人上,但是要求两个机器人之间不能有其他机器人

每次传递,只能由其中一个机器人传递给另一个,任意机器人可以作为起点。

问所有机器人被电到能形成几种图形,

有些机器人不能电到输出-1



解题:

1. 用计算几何处理,把相互可达的点记录下来用假设Dist[i][j]=1 表示i,j可达

  dist[i][j] = 0表示i,j不可达,i=j,dist[i][j]=0;


 2. 有个生成树计数算法。百度一下,

    意思是A[i][j] i!=j A[i][j] =0;

    i==j    A[i][i]表示与i相连的边数

   另D = A-Dist

则D的任意一个n-1阶的行列式就是答案。

高斯消元算行列式


3. 数字可能很大要取模

要计算逆元   求a关于p的逆元

      另ax+py=1

x就是a的逆元


#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<math.h>
using namespace std;
#define ll long long
#define maxn 307
#define mod 10007
struct Point{
    int x,y;
    Point (int x=0,int y=0):x(x),y(y){}
};
int Length(Point a){
    return a.x*a.x+a.y*a.y;
}
Point operator-(Point a,Point b){
    return Point(a.x-b.x,a.y-b.y);
}
int Cross(Point a,Point b){
    return a.x*b.y-a.y*b.x;
}

int Dot(Point a,Point b){
    return a.x*b.x+a.y*b.y;
}
int Onsegment(Point a,Point b,Point c){
    if(Cross(a-c,b-c) != 0) return 0;
    if(Dot(a-b,a-c) < 0) return 1;
    return 0;
}
Point point[maxn];
int dist[maxn][maxn];

void getDist(int n,int r){
    memset(dist,0,sizeof(dist));
    int flag ;
    for(int i = 0;i < n; i++){
        for(int j = i+1;j < n;j++){
            if(Length(point[i]-point[j]) <= r*r){
                flag = 0;
                for(int k = 0;k < n; k++){
                    if(k == i || k == j) continue;
                    if(Onsegment(point[k],point[i],point[j])){
                        flag = 1; break;
                    }
                }
                if(flag == 0) dist[i][j] = dist[j][i] = 1;
            }
        }
    }
}

int inv[mod+10];

void gcd(int a,int b,int &x,int &y){
    if(b == 0 ){
        x = 1;
        y = 0;
        return ;
    }
    gcd(b,a%b,x,y);
    int y1 = y;
    y = x-a/b*y;
    x = y1;
}

int check[maxn];
int dfs(int u){
    if(check[u]) return 0;
    check[u] = 1;
    int ans = 1;
    for(int i = 0;i < maxn; i++)
        if(dist[u][i] == 1)
         ans+=dfs(i);
    return ans;
}
struct Matrix{
    int matrix[maxn][maxn];
    void init(){
        memset(matrix,0,sizeof(matrix));
    }
    int Det(int n,  int mod1){
        int ans = 1;

         for(int i = 0;i < n;i++)
            for(int j = 0;j < n;j++)
                matrix[i][j] = (matrix[i][j]+mod1)%mod1;


        for(int i = 0;i < n; i++){
            int p=i,x=matrix[i][i];
            //寻找列主元
            for(int j = i+1;j < n; j++){
                if(abs(matrix[j][i]) > abs(x)){
                    x = matrix[j][i];
                    p = j;
                }
            }
            for(int j = i;j < n; j++)
                swap(matrix[p][j],matrix[i][j]);

            if(p != i) ans = -ans;
            if(ans < 0) ans+=mod1;
            if(matrix[i][i] == 0) return -1;
            ans = ans*matrix[i][i]%mod1;
            matrix[i][i] %= mod1;
            if(matrix[i][i] < 0) matrix[i][i]+=mod1;
            matrix[i][i] = inv[matrix[i][i]];
            for(int j = i+1;j < n; j++){
                if(matrix[j][i] == 0) continue;
                matrix[j][i] = (matrix[j][i]*matrix[i][i])%mod1;
                for(int k = i+1;k<n;k++){
                    matrix[j][k] = (matrix[j][k]-matrix[i][k]*matrix[j][i])%mod1;
                    if(matrix[j][k] < 0) matrix[j][k]+=mod1;
                }
            }

        }
        return (ans%mod1+mod1)%mod1;
    }
};

int main(){
    int n,t,r,x,y;
    Matrix mat;
    for(int i = 1;i < mod;i++){
        gcd(i,mod,x,y);
        inv[i] = (x%mod+mod)%mod;
    }

    scanf("%d",&t);
    while(t--){
        scanf("%d%d",&n,&r);
        for(int i = 0;i < n; i++)
            scanf("%d%d",&point[i].x,&point[i].y);
        getDist(n,r);

        memset(check,0,sizeof(check));
        if(dfs(0) != n){
            printf("-1\n");
            continue;
        }

        mat.init();
        for(int i = 0;i < n; i++)
            for(int j = 0;j < n; j++){
                if(dist[i][j] == 1){
                    mat.matrix[i][j] = -1;
                    mat.matrix[i][i]++;
                }
            }
        int ans = mat.Det(n-1,mod);

        printf("%d\n",ans);
    }
    return 0;
}
























你可能感兴趣的:(高斯消元,计算几何,逆元)