日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Prufer序列 生成树定理

發布時間:2023/12/3 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Prufer序列 生成树定理 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Description

在圖論中,樹的定義是連通且無環的無向圖。對于一棵有?nn?個節點且節點從?11?到?nn?編號的樹,它的 Prufer 序列是一個唯一的長為?n?2n?2?的標號序列。 Prufer 序列的構造方法:每次刪除樹中標號最小的葉子節點(即度為?11?的節點),將該點的鄰居加到當前 Prufer 序列的末尾,直到只剩兩個節點為止。

例子:

給定一個?nn?個頂點(從?11?到?nn?標號),?mm?條邊的無向圖?GGGG?中無重邊或自環)。隨機選擇?GG?的一棵生成樹,計算他的 Prufer 序列的和?SS重復元素只算一次。 請計算隨機變量?SS?的期望。注意,GG?的生成樹或某棵生成樹的 Prufer 序列都可能不存在,這種情況下,我們認為隨機變量?SS?的值為?00

為了避免精度問題, 算出實際的期望值乘以圖?GG?的不同生成樹的數目以后的值即可。 這個值可能很大,請輸出它對?109+7109+7?取模以后的值。

Input

每個輸入文件包含多組測試數據。輸入文件的第一行是測試數據組數?TT?(T10T≤10)。 對于每組測試數據,第一行是兩個整數?n,mn,m?(3n100,0m(n?1)n23≤n≤100,0≤m≤(n?1)n2?),分別是圖的點數和邊數;接下來?mm?行,每行包含兩個整數?u,vu,v1u,vn1≤u,v≤nuvu≠v),表示圖中的一條邊。

Output

輸出?TT?行,每行是對應的答案。

Sample Input

1 3 3 1 2 2 3 1 3

Sample Output

6

題目大意:求所有生成樹的prufer序列和(prufer中有重復序列的只算一次!!!)

題解:

這樣的話,對于每一顆生成樹,我們可以把所有的點全都加進去,然后再減去葉子結點的和。

我們不可能找到所有的生成樹然后一個一個的計算,因此我們用矩陣樹定理來做。

我們先計算圖所有的點的和,并且乘以生成樹的數量,把他們放在sum里。然后再把所有的葉子結點減去,就好了

如果一個葉子節點出現在一顆子樹里,那么把這個點去掉,仍然可一得到圖的該生成樹,而如果這個點是內部節點就不行了。

注意:如果這個葉子節點的度不為1,那么要用這個葉子節點的度數乘以生成樹的數量,才是這個葉子節點對應生成樹的個數。

sum -= 去掉該節點生成樹的數量*該節點的度*該節點的值。

最后得到的sum就是答案

代碼:

#include<iostream>。 #include<cmath> #include <cstring> using namespace std; #define zero(x)((x>0? x:-x)<1e-15) #define int long long int const MAXN = 105; const int mod = 1e9 + 7; int a[MAXN][MAXN]; int b[MAXN][MAXN]; int g[103][103]; int d[105]; int n, m; int det(int a[MAXN][MAXN], int n){ int s=0;for(int i=0; i<n; i++){ int r=i; for(; r<n; r++) // error-prone if(a[r][i]) break; if(r==n+1) return 0; if(r!=i){ s^=1; for(int j=i; j<n; j++) swap(a[i][j], a[r][j]); } for(int j=i+1; j<n; j++){ int x=i, y=j; for(; a[y][i]; ){ // print(a, n); int t=a[y][i]/a[x][i]; if(t){ for(int k=i; k<n; k++){ a[y][k] -= t*a[x][k]%mod; a[y][k] %= mod; } if(a[y][i]==0) break; } swap(x, y); } if(x!=i){ for(int k=i; k<n; ++k) swap(a[x][k], a[y][k]); s ^= 1; } } } int res=1; for(int i=0; i<n; i++) res*=a[i][i], res%=mod; if(s){ res=-res; }if(res < 0) res+=mod; return res; } void prep(int n,int x) {for(int i = 0;i < n;i++){for(int j = 0;j < n;j++){a[i][j] = (i == j)?d[i]-g[i][x]:-g[i][j];}}if(x + 1){for(int i = 0;i < n;i++) a[x][i] = a[i][x] = 0;a[x][x] = 1;} }main() { int cas;scanf("%lld", &cas);while (cas--) {memset(g,0,sizeof(g));memset(d,0,sizeof(d));memset(a,0,sizeof(a));memset(b,0,sizeof(b));scanf("%lld%lld", &n,&m);for(int i = 0;i < m;i++){int u,v;scanf("%lld%lld",&u,&v);u--,v--;d[u]++;d[v]++;g[u][v] = g[v][u] = 1;}prep(n,-1);int sum = det(a,n-1)*((1+n)*n/2) % mod;for(int i = 0;i < n-1;i++){prep(n,i);sum = (sum - (i+1)*d[i] % mod * det(a,n-1) % mod + mod)%mod;//cout<<':'<<sum<<endl;}prep(n,n-1);sum = (sum - n*d[n-1] % mod * det(a,n-2) % mod + mod)%mod;cout<<sum<<endl;}return 0; }




總結

以上是生活随笔為你收集整理的Prufer序列 生成树定理的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。