給n個節點m條邊,構造一些無向圖,構造出來的圖需要滿足以下條件:
(1)圖中沒有自環
(2)圖中每個點的度最大是2
(3)圖中連通塊大小最大為L
問能構造出多少個這樣的圖出來,答案可能很大,對1e9+7取模
輸入格式
第一行三個整數n,m,L
2<=n<=300,1<=m,L<=n
輸出格式
一個整數
輸入/輸出例子1
輸入:
3 2 3
輸出:
3
樣例解釋
無
在瞭解此題前,我們先學一些前置知識
前置知識
環和鏈的重複性
1.對於一個鏈,反轉一下還是同一副圖,例如:
2.對於一個環,把圖翻過來還是同一幅圖
想成立體空間,把這個圖反轉過來,這樣的圖是同一個圖
根據點數計算不同鏈的數量
對於一個鏈
n個節點,構成的不同圖數量
n! / 2
很簡單,因為會有重複,把鏈反轉還是同一個鏈,所以結果要除二
根據點數計算不同環的數量(圓排列,項鍊排列)
對映思想
今天的第一個思想:運用對映思想
如果算A集合很難算,但我知道B集合有多少個,且B與A有關係,那麼就可以用B對映A
例如,我們想求A集合內成員數量,但是正面無法算,可是我們知道B集合有5個成員,且1個A集合相當於5個B集合,那麼A集合成員數量就可以透過B集合成員數量推出來,即 A集合數量=B集合數量*5 = 5*5 = 25
這裡引入幾個概念
圓排列
圓排列:對於n個節點能構成多少個不同的圓,注意是二維(2D)的,就是在一個二維平面,順時針看不一樣才算不同排列
正面算很難是吧,假設此時n=3
根據對映思想,我們可以算出全排列數量,即線性排列數量,很好算嘛,n! 種
然後我們再算一個圓(任意一個),它對應的排列數量,怎麼求?我們可以先暫時割掉一個邊,然後再dfs就出來順序了,如上圖
先割掉(1,3)這條邊,我們dfs一遍,就是{1,2,3},那麼這就是一個排列了,由於一共可以割掉n條邊,所以有n種
一個圓對應這麼多個排列數量,我們總共有那麼多個排列數量,我們用總共/單個,不就算出來數量了嗎
即 n! / n = (n-1)!
簡化:假設有n個點,那麼有n!種線性排列,有n個圓上面的排列(n個切割點)
至此推出了圓排列公式:(n-1)!
項鍊排列
項鍊排列:對於n個節點能構成多少個不同的圓,注意是二維(3D)的,就是在一個三維平面,順時針看不一樣也算同一個排列
假設有n個點,那麼有n!種線性排列,有(n-1)!圓排列,我們觀察一下圓排列和項鍊排列可以觀察出一個規律:
假設n=3,那麼這個項鍊排列有2個(固定著1,把圖反轉一下,運用空間想象力哈),根據圓排列計算公式,(n-1)!=(3-1)!=2!=2,那麼把這些值加在一起就可以發現規律了!
圓排列是項鍊排列的2倍
至此推出了項鍊排列公式:(n-1)! / 2
本題做法
根據題意,圖會構成:
1) 一條鏈,邊數=點數-1
2) 一個環,邊數=點數
邊數和點數有一種對應關係,所以我們可以根據點數推邊數
f[i][j]:一共考慮了i個點,j條邊,連通塊數量小於等於L的方案數
如果直接算等於L的方案數比較難,我們可以用算出來的DP,求出L - (L-1) 的方案數就是L的方案數了
這就是做差思想
我們假設新加入k個點,和圖原來的構成:
1)鏈的情況
現在加入k個點,相當於加入k-1條邊
在他之前的圖,有i-k個點,j-(k-1)條邊
那麼i,j的狀態肯定由i-k,j-(k-1)轉移過來的對吧
我們還需要考慮貢獻。
這k個點從要考慮從哪個集合裡面選,選出來後的點還有考慮如何排列。
我們先考慮從那裡選對吧,答案很顯然,從n個點裡面選,那麼有多少選擇方法?
首先之前圖的點數不可再選了,那麼剩餘的就是可以選的
即 總共可選點數 - 之前圖的點數
C(n-(i-k), k)
注意重複情況!我們選k個節點,可以分別考慮每個點
第一次:選1 2 3
第二次:選1 3 2
那不就重複了嗎,要去重
去重技巧:可以理解為排序,它是有一種順序的。我們讓最小點先進入選擇的序列中,一定要放進去!這樣後面選進來的點就不重複了
即 C(n-(i-k)-1, k-1)
選出來後考慮如何排列
這很簡單,選出來了k個點,那麼就是 k!種排列,由於選出來的點最終構成鏈,那麼有重複情況/2即可,前置知識嘛!
排列數量:k! / 2
轉移方程整理一下變成:
f[i][j] = (f[i][j] + f[i-k][j-k+1] * C(n-i+k-1, k-1) * k! / 2)
2)環的情況
現在加入k個點,相當於加入k條邊
原來圖點數 i-k,邊數 j-k
和鏈情況同樣,不過注意由於選出來的k個點要構成一個環,排列數量就是項鍊排列,也就是 (n-1)! / 2
轉移方程:
f[i][j] = (f[i][j] + f[i-k][j-k] * C(n-i+k-1, k-1) * (k-1