HDOJ 4305 – Lightning 判斷點線上段上+構造Matrix Tree求產生樹的個數+高斯消元

來源:互聯網
上載者:User

             題意:

                       有N個點在二維平面上...兩點間若距離不大於R並且構成的線段中沒有其他的點..則可以連一條邊..現在問..這個圖有多少個產生樹

             題解:

                       覺得這題好屌...一些計算幾的知識+神奇的矩陣+高斯消元(同時要求逆元)...

                       先構邊...按照題目的要求..ok的就有邊...構邊就直接構造Matrix Tree吧...而Matrix Tree構造的矩陣意思是: 對角線上為每個點的度..非對角線上為兩點間連著邊的個數的相反數..由於本題沒有重邊.那麼就是有邊則為-1..沒邊則為0...構造出矩陣..去掉任意一個十字..剩下的行列式之合就是該圖的產生樹的個數..好神奇..不懂如何證明...直接拿來用了...最後就是要求一個矩陣的行列式...方法有很多種...一般都是用高斯消元...高斯消元的方法是每次讓一列只剩下一個數..其他數約掉...最後矩陣轉化為一個上三角..對角線乘積則為矩陣的行列式...手算的時候一般會出現幾分之幾...程式如果也用double來寫最後又回到int..可能會產生一些精度問題..但高斯消元是可以讓每一步都是整數的.如本題..由於最後的答案要mod一個數...當要做除法時..直接用逆元就好..若沒有模數運算..那麼就先對所有行做lcm...然後再消...

Program:

#include<iostream>#include<stdio.h>#include<string.h>#include<cmath>#include<queue>#include<stack>#include<set>#include<time.h>#include<map>#include<algorithm>#define ll long long#define eps 1e-5#define oo 10007#define pi acos(-1.0)#define MAXN 305using namespace std;   struct node{      int x,y;      node () {}      node ( int x , int y ) : x(x) , y(y) {}}p[MAXN];typedef node Vector;Vector operator - ( node a , node 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 dis(node p1,node p2){      return (p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y);}int Cross (Vector a , Vector b ){    return a.x*b.y - a.y*b.x;}bool InLine(node p1,node p2,node p3){      return Cross ( p1 - p2 , p3 - p2 ) == 0 && Dot ( p1 - p2 , p3 - p2 ) < 0;      }int C[MAXN][MAXN]; void exgcd(int a,int b,int &x,int &y){        if(b==0) { x=1,y=0; return; }      exgcd(b,a%b,x,y);        int t;        t=x,x=y,y=t-a/b*y;        return;  } int det(int n)//計算n階行列式的絕對值%mod  {        int ans=1,flag=1;//flag行列交換的次數..為奇數則要*-1       int i,j,k;        for(i=0;i<n;i++)        {             if(C[i][i]==0)             {                   for(j=i+1;j<n;j++)                       if(C[j][i])break;                   if(j==n) return 0;//某列的值全是0的ans=0;                   flag=!flag;                   for(int k=i;k<n;k++) swap(C[i][k],C[j][k]);//i和j行交換             }             ans=ans*C[i][i]%oo;//對角線相乘             int x,y;             exgcd(C[i][i],oo,x,y);//x為逆元.若沒有模數運算那就需要LCM再來化            for(k=i+1;k<n;k++) C[i][k]=C[i][k]*x%oo;             for(int j=i+1;j<n;j++)                for(int k=i+1;k<n;k++)                {                      C[j][k]=(C[j][k]-C[j][i]*C[i][k])%oo;                      C[j][k]=(C[j][k]+oo)%oo;                }        }        ans=(ans%oo+oo)%oo;        if(flag) return ans;           else  return oo-ans;  }    int main(){           int T,N,R,i,j,x;       scanf("%d",&T);      while (T--)      {             scanf("%d%d",&N,&R);             R*=R;             for (i=0;i<N;i++) scanf("%d%d",&p[i].x,&p[i].y);             memset(C,0,sizeof(C));             for (i=0;i<N;i++)                for (j=i+1;j<N;j++)                   if (dis(p[i],p[j])<=R)                   {                         for (x=0;x<N;x++)                            if (InLine(p[i],p[x],p[j])) goto A;                         C[i][i]++,C[j][j]++;                         C[i][j]=C[j][i]=-1;                         A: ;                   }              x=det(N-1);             if (!x) x=-1;             printf("%d\n",x);      }      return 0;}  

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.