生成樹個數(基爾霍夫矩陣)
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) 簡單來說,熵是表示物質系統狀態的一種度量,用它老表徵系統的無序程度。熵越大,系統越無序,意味著系統結構和運動的不確定和無規則;反之,,熵越小,系統越有序,意味著具有確定和有規則的運動狀態。熵的中文意思是熱量被溫度除的商。負熵是物質系統有序化,組織化,複雜化狀態的一種度量。 熵最早來