1. 程式人生 > >hdu4305Lightning 生成樹計數(基爾霍夫矩陣)+高斯消元+逆元

hdu4305Lightning 生成樹計數(基爾霍夫矩陣)+高斯消元+逆元

題意:比較裸的生成樹計數問題。

  如何處理生成樹計數問題?

基爾霍夫矩陣:

if i==j  Kir[i][j] = i的度數

if i!=j   Kir[i][j] = i到j的平行邊的個數的負數

即,基爾霍夫矩陣 = 度數矩陣 - 鄰接矩陣

基爾霍夫矩陣刪去第i行和第i列,餘下i-1階的行列式的值即為生成樹個數。(證明略)

求行列式的值可以將行列式轉為上三角陣,求對角線上的積即為行列式的值。

可以用高斯消元的方法轉換上三角陣,過程中要mod p,除法改為逆元。

程式碼:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 400+10;
typedef long long ll;
const ll mod = 10007;

struct point{
    int x,y;
    int id;
}p[N];
bool d[N][N],f[N][N];
int T,n,r;
int flag = 0;
ll dis(point a,point b){
    return (a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y);
}
int online(point a,point b,point c){
    return (ll)(a.x-c.x)*(b.y-c.y) == (ll)(b.x-c.x)*(a.y-c.y);
}
void build(){
    memset(d,0,sizeof(d));

    for(int i=0;i<n;i++)
    for(int j=0;j<n;j++) if(i!=j){
        if(dis(p[i],p[j]) <= (ll)r*r){
            int ok = 1;
            for(int k=0;k<n;k++)if(k!=i&&k!=j){
                if( (p[i].x<=p[k].x && p[k].x<=p[j].x)||(p[j].x<=p[k].x && p[k].x<=p[i].x) ){
                    if(online(p[i],p[j],p[k])){
                        ok = 0;
                        break;
                    }
                }
            }
            if(ok) d[i][j]=1;
        }
    }

    for(int i=0;i<n;i++)
    for(int j=0;j<n;j++) f[i][j]=d[i][j];

    for(int k=0;k<n;k++)
    for(int i=0;i<n;i++)
    for(int j=0;j<n;j++)
        f[i][j] = f[i][j] | (f[i][k]&&f[k][j]);

    flag = 1;
    for(int i=0;i<n;i++)
    for(int j=0;j<n;j++)
    if(!f[i][j]) flag = 0;
}

ll exgcd(ll a,ll b,ll &x,ll &y)//乘法逆元返回的d是a,b的公約數,x是a mod b的逆元
{
    if(b==0)
    {
        x=1ll;y=0;
        return a;
    }
    ll d=exgcd(b,a%b,x,y);
    ll t=x;
    x=y;
    y=t-a/b*y;
    return d;
}
ll Gauss(int C[][N],int n)//計算n階行列式的絕對值 % mod
{
    ll ans=1ll;
    int 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]%mod;//對角線相乘
      ll x,y;
      int tp=exgcd(C[i][i],mod,x,y);//x為逆元


      for(k=i+1;k<n;k++)
        C[i][k]=C[i][k]*x%mod;


      for(int j=i+1;j<n;j++)
      for(int k=i+1;k<n;k++)
      {
          C[j][k]=(C[j][k]-(ll)C[j][i]*C[i][k])%mod;
          if(j==k)
          C[j][k]=(C[j][k]+mod)%mod;
      }
      for(k=i+1;k<n;k++)
        C[i][k]=(ll)C[i][k]*C[i][i]%mod;

    }


    ans=(ans%mod+mod)%mod;
    if(flag) return ans;
    else  return mod-ans;
}

int Kir[N][N];
int solve(){
    memset(Kir,0,sizeof(Kir));
    for(int i=0;i<n;i++)
    for(int j=0;j<n;j++)
        Kir[i][i] += d[i][j];
    for(int i=0;i<n;i++)
    for(int j=0;j<n;j++)
        Kir[i][j] -= d[i][j];

    return Gauss(Kir,n-1);
}
int main(){
    cin >> T;
    while(T--){
//        cin >> n >> r;
        scanf("%d%d",&n,&r);
        for(int i=0;i<n;i++){
            scanf("%d%d",&p[i].x,&p[i].y);
            p[i].id = i;
        }
        build();
        if(flag==0){
            puts("-1");
            continue;
        }
        ll ans = solve();
//        cout<<ans<<endl;
        printf("%d\n",(int)ans);
    }
    return 0;
}


相關推薦

hdu4305Lightning 成樹計數矩陣++

題意:比較裸的生成樹計數問題。   如何處理生成樹計數問題? 基爾霍夫矩陣: if i==j  Kir[i][j] = i的度數 if i!=j   Kir[i][j] = i到j的平行邊的個數的負數 即,基爾霍夫矩陣 = 度數矩陣 - 鄰接矩陣 將基爾霍夫矩陣刪去第i

成樹個數矩陣

Problem 2. tcount Input file: tcount.in Output file: tcount.out Time limit: 1 second Mr.H發現了一個無向連

生成成樹計數 --- Matrix-Tree定理(矩陣樹定理)

模板題點這 題目大意: *一個有n座城市的組成國家,城市1至n編號,其中一些城市之間可以修建高速公路; *需要有選擇的修建一些高速公路,從而組成一個交通網路; *計算有多少種方案

【hdu5304】成樹計數矩陣 DP

給一個無向圖,求有多少個子圖是基環樹。 列舉環後縮點,再求生成樹計數。 2^n列舉環上的點,dp預處理出每個集合的環的個數(預設以編號最小的點為起點),用f[i][s]表示環尾為i,點集為s。 #include <iostream> #include <c

BZOJ 1002 - 輪狀病毒 - [矩陣待補+精度][FJOI2007]

() out strlen esp lean 例如 計算 stream height 題目鏈接:https://www.lydsy.com/JudgeOnline/problem.php?id=1002 Description  輪狀病毒有很多變種,所有輪狀病毒的變種都是從

BZOJ1494: [NOI2007]成樹計數Berlekamp-Massey演算法

傳送門 題解: 直接打表+BM算出遞推式,BM具體實現可以戳這裡 附上一份其醜無比的BM程式碼: const int L=4e2; namespace bm { int cnt,a[N],fail[N],delta[N]; vector <int> R[N]

成樹計數Matrix-Tree定理

以下轉載自http://blog.csdn.net/jarily/article/details/8901363 /* *演算法引入: *給定一個無向圖G,求它生成樹的個數t(G); * *演算法思想: *(1)G的度數矩陣D[G]是一個n*n的矩陣,並且滿足:

【BZOJ1494】【NOI2007】成樹計數動態規劃,矩陣快速冪

題面 Description 最近,小棟在無向連通圖的生成樹個數計算方面有了驚人的進展,他發現: ·n個結點的環的生成樹個數為n。 ·n個結點的完全圖的生成樹個數為n^(n-2)。這兩個發現讓小棟欣喜若狂,由此更加堅定了他繼續計算生成樹個數的 想法,他

電路 - 定律KLL;節點流入電流等於流出電流。

定律 公式 通過 假設 mage 14. 一個 表示 nbsp 下面是我在學習STM32 中ADC測量電壓,時候接觸掉ADC的測量範圍在0~3.3V 之間,不滿足於實際使用,用於電路知識設計電壓放大電路。(圖片來自野火) 上面個的電路,可以等效出一個電路公式:(

統計自然語言處理模型

目的 1.瞭解什麼馬爾科夫模型的三個問題 ·狀態概率的計算(前向演算法) ·馬爾科夫譯碼過程(維特比演算法) ·馬爾科夫引數求解(EM演算法 前後向演算法) 隱馬爾科夫模型(HMM) 這裡筆者假設大家大致瞭解馬爾科夫模型,即馬爾科夫鏈的節點狀態

實現求解線性方程矩陣去法------c++程序設計原理與實踐進階篇

ipy 類型 cat sys sca solution gaussian 拷貝 img 步驟: 其中A是一個n*n的系數方陣 向量x和b分別是未知數和常量向量: 這個系統可能有0個、1個或者無窮多個解,這取決於系數矩陣A和向量b。求解線性系統的方法有很多,這裏使用一種經典

kuangbin專題八 UVA10766 成樹計數Organising the Organisation請無視這篇文章

題意: 給出n,m,k,代表一家公司有n個部門,編號1到n,有m組關係,表示i和j不能直接聯通,k代表主管部門,問你有多少種分層方案。另外,這道題的k可以忽略掉,所以他的範圍完全是嚇唬人的。 題解: 抱歉,這道題我真的無法弄的通俗的說出來

kuangbin專題八 URAL1627 Join成樹計數

題意: 給出一個圖,’.’表示臥室,’*’表示儲藏間,每個格子上下左右都有一堵牆,然後需要打通一些臥室的牆(只能是相鄰房間才能打通)使得臥室之間聯通的方案數. 給每個臥室編個號,給可以打通的臥室加邊,就是裸的生成樹計數了. 題解: 打通一

UVA 10766 Organising the Organisation成樹計數 不取模

Problem H Organising the Organisation Input: Standard Input Output: Standard Output Time Limit: 2 Second I am the chief of the Personne

uva10766成樹計數

als mes art 算子 技術分享 math 個數 main mat 此類題是給定一個無向圖,求所有生成樹的個數,生成樹計數要用到Matrix-Tree定理(Kirchhoff矩陣-樹定理) G的度數矩陣D[G]是一個n*n的矩陣,並且滿足:當i≠j時,dij=0;當i

hdu4305成樹計數

open assert with for def com false tor == 先預處理出距離,然後判斷是否可行,要註意判斷是否在一條直線上時判斷是在兩側還是一邊(wa了四次) double型數據 #include<map> #include<se

成樹計數及應用 Matrix-Tree

log blog 生成樹計數 mathjax 插值 tps 生成樹 www. 應用 例:給定一個圖,圖上每條邊是紅色或藍色,求恰有 k 條紅邊的生成樹個數. n≤50. Matrix-Tree定理,對於限制條件可以利用多項式,把紅邊邊權設為 X,藍邊為1. 最後求行列式得到

【LOJ】#2320. 「清華集訓 2017」成樹計數

rac res 然而 除了 加法 wap OS 代碼 reg 題解 我,理解題解,用了一天 我,卡常數,又用了一天 到了最後,我才發現,我有個加法取模,寫的是while(c >= MOD) c -= MOD 我把while改成if,時間,少了 六倍。 六倍。 六倍!!

[BZOJ1494]成樹計數

cto operator 個數 最後一行 判斷 state for break desc [BZOJ1494] [NOI2007]生成樹計數 Description 最近,小棟在無向連通圖的生成樹個數計算方面有了驚人的進展,他發現:·n個結點的環的生成樹個數為n。·n個結點

bzoj1494 成樹計數 (dp+矩陣快速冪)

sets 增加 set 基本 表示 2種 least 欺詐 main 題面欺詐系列... 因為一個點最多只能連到前k個點,所以只有當前的連續k個點的連通情況是對接下來的求解有用的 那麽就可以計算k個點的所有連通情況,dfs以下發現k=5的時候有52種。 我們把它們用類似於並