內向樹的生成樹計數

2021-08-14 06:23:19 字數 2737 閱讀 4461

所謂內向樹,就是樹上的邊是由兒子指向父親

來看乙個題

元首把花園分為 nn

n 行 mm

m 列的網格。每個格仔中都可以放置乙個標識,指向上、下、左、右四個方向中的任意乙個。元首位於乙個格仔時,會按照其中標識所指的方向進入周圍的格仔,或者走出花園(即目的格仔不在網格之內)。舉個例子 —— 對於下面的放置方式,元首從第 33

3 行第 22

2 列的格仔開始,會沿著以紅色標出的路徑走出花園;從第 22

2 行第 22

2 列的格仔開始,則會在以藍色標出的環路內不斷地行走。

← →↓← ↑ ←↓

← ↑→↓ ←

元首已經設計好了大部分格仔的標識。元首用字元lrud分別表示指向左、右、上、下四個方向的標識,用字元.表示未決定的格仔。現在,元首希望將每個.替換為lrud中任意一種,使得從花園中的任意乙個格仔出發,按照上述規則行走,都可以最終走出花園。

你需要編寫程式幫助元首計算替換的不同方案數。兩個方案不同當且僅當存在乙個格仔,使得兩個方案中該格仔內的標識不同。當然,由於答案可能很大,只需給出方案數除以 109+710^9 + 710

​9​​

+7所得的餘數即可。

對於此題,我們對於邊界外建立乙個點(n*m+1),網格每個點向指出去的點連邊,未知的點,它的連邊方式有4種,求生成樹的個數

這題的生成樹邊是單向的,且都由孩子指向父親,我們管它叫內向樹的生成樹計數,然後結論就是:另鄰接矩陣為g,出度矩陣為d,那麼d-g的任意乙個n-1行n-1列子矩陣的行列式就是生成樹的個數

你要問我為什麼是這樣的,我這麼,怎麼可能會嘛。。。

因為這題的點數太大了,如果直接建立矩陣肯定是不行的,但是我們發現對答案有影響的就是指向未知的點,那麼就可以只提取出那些關鍵點(題目保證了關鍵點個數只有300個),那麼我們在這300個點之間建立關係求行列式就好了。

注意的是一開始需要判斷,因為已知方向的點可能已經構成環了,我的方法如下:一開始對於那些已知方向的點,用並查集縮點,然後已知方向的點的聯通塊只能有乙個(指向n*m+1)。

#include#include#include#include#includeusing namespace std;

const int maxn = 305;

const int mod = 1000000007;

int d[maxn][maxn], g[maxn][maxn], f[maxn][maxn];

int n, m, t, i, j, k, fa[maxn * maxn], x[maxn], y[maxn], cnt, num[maxn * maxn];

int dx[4] = , dy[4] = ;

char s[maxn][maxn];

inline int find(int x)

inline int point(int x, int y)

inline int ksm(int x, int y, int z)

return b;

}int main()

int xx = find(point(i, j)), yy;

if (s[i][j] == 'u') yy = find(point(i - 1, j));

if (s[i][j] == 'd') yy = find(point(i + 1, j));

if (s[i][j] == 'l') yy = find(point(i, j - 1));

if (s[i][j] == 'r') yy = find(point(i, j + 1));

fa[xx] = yy;

}int block = 0;

for(i = 1; i <= n * m + 1; i ++)

if (find(i) == i) block ++;

if (block > cnt + 1)

for(i = 1; i <= cnt; i ++)

num[point(x[i], y[i])] = i;

for(i = 1; i <= cnt + 1; i ++)

for(j = 1; j <= cnt + 1; j ++)

g[i][j] = d[i][j] = 0;

num[n * m + 1] = cnt + 1;

for(i = 1; i <= cnt; i ++)

for(j = 0; j < 4; j ++)

for(i = 1; i <= cnt; i ++)

for(j = 1; j <= cnt; j ++)

int ans = 1;

for(i = 1; i <= cnt; i ++)

if (!k) continue;

if (k != i)

for(j = i + 1; j <= cnt; j ++)

}for(i = 1; i <= cnt; i ++)

ans = 1ll * ans * f[i][i] % mod;

if (ans < 0) ans += mod;

cout << ans << endl;

}}

生成樹計數

考慮簡單帶權無向圖的情況。約定這張圖為 g v,e n v m e e i u i,v i,w i 表示第 i 條邊,deg u 表示 u 所連邊的邊權和。mathbf a 滿足 mathbf a w i,j mathbf d 滿足 mathbf d i j deg i mathbf b 滿足 ma...

Lightning(生成樹計數)

原題 題意 n個點,任意兩個點之間可以連邊當且僅當距離不大於r,並且中間沒有其他邊。求生成樹個數。解析 判斷中間有沒有點可以直接n3for,也可以n2log,列舉每個點為起點,其他的點與之形成的向量用map比較是否存在即可。連完邊就用矩陣樹進行n3做就行了。include using namespa...

無標號生成樹計數

做模擬賽的時候碰到了,感覺稍微有點意思,寫來自己看。無標號有根樹 設f n 表示樹的大小為 n 的方案數,其生成函式f z n 0f nzn。考慮生成函式的組合意義,fn 1可以由若干個無序的不同大小的 若干個無序的相同大小的本質不同的子樹 拼成,對於大小為 k 的樹,作為多棵子樹時他可以貢獻的不同...