藍魔法師 樹形DP

2021-09-20 18:47:27 字數 1331 閱讀 6636

時間限制:c/c++ 1秒,其他語言2秒

空間限制:c/c++ 262144k,其他語言524288k

64bit io format: %lld

「你,你認錯人了。我真的,真的不是食人魔。」--藍魔法師

給出一棵樹,求有多少種刪邊方案,使得刪後的圖每個連通塊大小小於等於k,兩種方案不同當且僅當存在一條邊在乙個方案中被刪除,而在另乙個方案中未被刪除,答案對998244353取模

第一行兩個整數n,k, 表示點數和限制

2 <= n <= 2000, 1 <= k <= 2000

接下來n-1行,每行包括兩個整數u,v,表示u,v兩點之間有一條無向邊

保證初始圖聯通且合法

共一行,乙個整數表示方案數對998244353取模的結果
示例1

複製

5 2

1 21 3

2 42 5

複製

7
不會樹形dp,思路參考於

用dp【u】【p】表示根節點為u的連通塊(包括u),它的連通塊大小為p時的方案數

其中dp【u】表示所有方案之和

這樣就是乙個計數問題,而計數問題最怕遺漏和重複,狀態該如何轉移呢?

對於它的乙個子節點v,當u訪問到v時,假設之前已經訪問了幾個子節點,之前訪問的節點個數為siz[u],那麼假設我們要讓連通塊大小為p,p可以從兩個地方來:從之前訪問過的節點中,也就是siz【u】,也可以從現在正在訪問的節點v,也就是siz【v】。那麼根據乘法計數原理,答案就是兩者相乘。

搜尋**如下:

for(int i=0;i所以整個**也就很好寫了。

#include #include #include #include #include #include using namespace std;

typedef long long ll;

const ll mod=998244353;

const int maxn=2000+10;

vectorg[maxn];

ll dp[maxn][maxn];

ll n,k;

ll siz[maxn];//每個節點的子節點個數

void dfs(int u)

} for(int j=1;j<=k;j++)

siz[u]+=siz[v];

} for(int i=1;i<=k;i++)

}int main()

memset(dp,0,sizeof(dp));

dfs(1);

printf("%lld\n",dp[1][0]);

}return 0;

}

樹形dp 組合數學 藍魔法師

dp i j 表示對於i這個子樹來說,i所在的連通塊大小為j,並且整棵樹合法的方案數。接下來就是類似揹包的解法了。遍歷每個兒子的分支,每個分支要麼刪除,要麼不刪除。1.刪除 刪除此邊,那麼就意味著當前以u節點連通塊大小為k的方案數 都可以 乘 v節點連通塊大小所有的方案數 2.不刪除 不刪除就相當於...

Wannafly27 C 藍魔法師 樹形DP

wannafly27 c 藍魔法師 給定一棵樹,刪除一些邊,使每個連通塊不超過k個節點 includeusing namespace std const int max 2e3 5 const int mod 998244353 int n,k struct p e max 1 int head m...

藍魔法師 牛客

將一顆 n 1 leq n leq 2000 個結點的樹,分成 t 1 leq t leq n 個連通塊,且每個連通塊的大小都小於或者等於 k 1 leq k leq 2000 求劃分方案數?dp i j 以 i 為根的子樹向父親結點 u 提供 j 個點的貢獻 dp fa i cnt 1 cnt 2...