1. 程式人生 > >生成樹個數(基爾霍夫矩陣)

生成樹個數(基爾霍夫矩陣)

Problem 2. tcount
Input file: tcount.in
Output file: tcount.out
Time limit: 1 second
Mr.H發現了一個無向連通圖,它覺得,如果選出一些邊來,使得這個圖變為一棵樹,那麼這個邊集就非常棒。
現在,Mr. H 想讓你幫忙求出有多少個非常棒的邊集?
Input
第1行,包含2個整數:n m,表示有n個點m條邊。
接下來m行,每行2個整數:u v,表示一條邊。
Output
輸出1行,包含1個整數,表示方案數模10^9 + 7。
Sample
tcount.in
3 3
1 2
2 3
1 3
tcount.out
3
tcount.in
4 6
1 2
1 3
1 4
2 3
2 4
3 4
tcount.out
16
Note
對於30% 的資料,1 <= n;m <= 12;
對於100% 的資料,1 <= n <= 100, 1 <= m <= n(n-1)/2
資料保證沒有重邊。

思路:
度數矩陣 a[i][i]為點i的度 其他位置為0
鄰接矩陣 a[i][i]=0; a[i][j]=[i與j相連]
基爾霍夫矩陣 = 度數矩陣 - 鄰接矩陣
Matrix-Tree 定理:
一個n個點m條邊的無向圖的生成樹總數為其對應的基爾霍夫矩陣的n-1階餘子式(行列式)。

行列式是什麼?
一種定義是:
det(A) = Σ (-1)^(i1i2..in) * a1i1 * a2i2 anin
i1i2..in

其中i1i2…in 是一個1到n的排列,^(i1i2..in) 表示該排列的逆序對個數
行列式的性質
1.某行乘一個數,那麼行列式也乘那個數。
2.某行加到另一行,行列式不變
3.交換兩行,行列式取反相反數(交換兩個數逆序對個數總是改變奇數個)
這裡寫圖片描述


行列式的計算—高斯消元!
消元的過程中行列式不變,交換一次行列式*-1。所以消元完成後,矩陣只剩下對角線上的主元。
根據行列式的要求,我們要在矩陣中每一行找出且只能找出一個數 每一列找出且只能找出一個數。
那麼就是對角線上的數了(只有一種排列),把對角線上的數乘起來就是行列式了。

由於中途有mod,double的除法又有可能炸精度。
所以有兩種解決方法,一個是輾轉相除,一個是逆元,下面的程式碼兩種都給出來了。

#include <iostream>  
#include <cstdio>  
#include <cmath>  
#define LL long long
using namespace std; const int MOD = 1e9+7; LL a[105][105]; int n, m, sign, du[105]; void solve(int N){ sign = 0; LL ans = 1; for(int i=1; i<N; i++){ for(int j=i+1; j<N; j++){//當前之後的每一行第一個數要轉化成0 int x=i, y=j; while( a[y][i] ){//利用gcd的方法,不停地進行輾轉相除 LL t = a[x][i] / a[y][i]; for(int k=i; k<N; k++) a[x][k] = (a[x][k] - a[y][k] * t) % MOD; swap(x, y); } if(x != i){//奇數次交換,則D=-D'整行交換 for(int k=1; k<N; k++) swap(a[i][k], a[x][k]); sign ^= 1;//行列式*-1 } } if( !a[i][i] ){//斜對角中有一個0,則結果為0 printf("0\n"); return ; } else ans = ans * a[i][i] % MOD; } if(sign != 0) ans *= -1; if(ans < 0) ans += MOD;// printf("%I64d\n", ans); return ; } int main(){ freopen ("tcount.in", "r", stdin); freopen ("tcount.out", "w", stdout); scanf("%d%d", &n, &m); for(int i=1; i<=m; i++){ int x, y; scanf("%d%d", &x, &y); a[x][y] = a[y][x] = -1; du[x]++; du[y]++; } for(int i=1; i<=n; i++) a[i][i] = du[i]; solve(n); return 0; }
#include <bits/stdc++.h>
using namespace std;

const int N = 110;
const int Mod = 1e9 + 7;

int n, m;
int aa[N][N];

int mpow(int a, int b) {
    int rt;
    for(rt = 1; b; b>>=1,a=(1LL*a*a)%Mod)
        if(b & 1) rt=(1LL*rt*a)%Mod;
    return rt;
}

int inverse(int a) {
    return mpow(a, Mod-2);
}

int det(int n) {
    int rt = 1;
    for(int i=1; i<=n; i++) {
        int j = -1, k;
        for(k=i; k<=n; k++)
            if(aa[k][i] != 0) {
                j = k;
                break;
            }
        if(j == -1) return 0;
        if(i != j) {
            for(k=i; k<=n; k++) {
                swap(aa[i][k], aa[j][k]);
                rt = (Mod - rt) % Mod;
            }
        }
        int inv = inverse(aa[i][i]);
        for(j = i + 1; j <= n; j++) {
            if(aa[j][i] == 0) continue;
            int r = 1LL * aa[j][i] * inv % Mod;
            for(k = i; k <= n; k++) {
                aa[j][k] -= 1LL * aa[i][k] * r % Mod;
                if(aa[j][k] < 0) aa[j][k] += Mod;
            }
        }
    }
    for(int i = 1; i <= n; i++)
        rt = 1LL * rt * aa[i][i] % Mod;
    return rt;
}

int main() {
    scanf("%d%d", &n, &m);
    for(int i=1; i<=m; i++) {
        int u, v;
        scanf("%d%d", &u, &v);
        aa[u][u]++;
        aa[v][v]++;
        aa[u][v] = aa[v][u] = Mod-1;
    }
    printf("%d\n", det(n-1));
}

相關推薦

成樹個數矩陣

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

hdu4305Lightning 成樹計數矩陣+高斯消元+逆元

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

生成成樹計數 --- 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  輪狀病毒有很多變種,所有輪狀病毒的變種都是從

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

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

統計自然語言處理模型

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

【HDOJ6229】Wandering Robots鏈,set

聯通 tin queue 開放 答案 轉移 first gcd 格子 題意:給定一個n*n的地圖,上面有k個障礙點不能走,有一個機器人從(0,0)出發,每次等概率的不動或者往上下左右沒有障礙的地方走動,問走無限步後停在圖的右下部的概率 n<=1e4,k<=1e3

最大成樹poj2377 和最小生成樹一個原理,只是排序的時候要降序排列

#include<cstdio> #include<algorithm> #include<cstring> using namespace std; const int maxn=1000+10; const int maxm=20000+10; struc

基於HMM隱馬和DNN的歌聲合成系統成果樣本

基於HMM(隱馬爾科夫鏈)和DNN的歌聲合成系統成果樣本 閒話少說 樣本連線 閒話少說 最近工作的一點成績。 樣本連線 日文歌曲1. 日文歌曲2.; 日文歌曲3.; 日文歌曲4.;

HMM隱馬模型

一、定義 從定義可以看出,隱馬爾可夫模型做了兩個基本假設: 二、 隱馬爾可夫模型的三要素:初始狀態概率矩陣、狀態轉移概率矩陣A、觀測概率矩陣 B  三、隱馬爾科夫的3個基本問題  3.1  概率計算演算法 3.1.1 直

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]

深度學習 --- 受限玻茲曼機過程、馬

        上一節我們詳細的探討了玻爾茲曼機,玻爾茲曼機的發明是為了解決Hopfield神經網路的偽吸引子的問題,因此把退火演算法、玻爾茲曼分佈和Hopfield神經網路結合在一起形成了玻爾茲曼機(隨機神經網路)。通過前面幾節我們知道玻爾茲曼機可以很好

網橋成樹網橋和源路由網橋

生成樹網橋: 網橋收到一個數據幀以後,執行地址表擴充和幀轉發,地址表擴充是指檢視信源結點地址,進行地址表的擴充,從而使網橋瞭解哪些節點在哪些子網中;幀轉發是指如果本地址表有信源地址裡所有的結點,則直接進行轉發;如果沒有,則傳送給本網橋所連線的所有子網(廣播) 此種方法得以

快速通俗理解HMM隱馬模型

導讀 本文的結構安排如下目錄。首先介紹了HMM的基本定義;然後引出HMM的3個基本問題中;在前兩個環節中通過一個淺顯易懂的案例幫助理解;其次是針對3個問題中用到演算法的理論介紹;最後介紹了預測天氣的HMM經典案例,並附有python程式碼。 目錄 案

成樹計數Matrix-Tree定理

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

Python實現HMM隱馬模型

前幾天用MATLAB實現了HMM的程式碼,這次用python寫了一遍,依據仍然是李航博士的《統計學習方法》 由於第一次用python,所以程式碼可能會有許多缺陷,但是所有程式碼都用書中的例題進行了測試,結果正確。 這裡想說一下python,在編寫HMM過程中參看了之前寫的M

機器學習 —— 概率圖模型與條件隨機場

種類 方向 方法 所有 href 個人 tro 傳遞 很好 機器學習 —— 概率圖模型(馬爾科夫與條件隨機場)   再一次遇到了Markov模型與條件隨機場的問題,學而時習之,又有了新的體會。所以我決定從頭開始再重新整理一次馬爾科夫模型與條件隨機場。   馬

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

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

一文搞懂HMM隱馬模型

什麼是熵(Entropy) 簡單來說,熵是表示物質系統狀態的一種度量,用它老表徵系統的無序程度。熵越大,系統越無序,意味著系統結構和運動的不確定和無規則;反之,,熵越小,系統越有序,意味著具有確定和有規則的運動狀態。熵的中文意思是熱量被溫度除的商。負熵是物質系統有序化,組織化,複雜化狀態的一種度量。 熵最早來