HDU 5378 Leader in Tree Land(树形背包+组合数学)

来源:互联网 发布:linux 特殊符号 编辑:程序博客网 时间:2024/04/28 17:24

题意:把1到n划分到n个结点的树中,子树的领导是这个子树中权值最大的点。求n个结点的树中,领导为k个的情况数。

思路:树形背包。用dp[i][j]表示以i为根的子树中领导为j个的情况数。

首先用siz[i]表示以i为根的子树中有多少结点。

考虑以i为根的子树,初始化dp[i][0] = siz[i] - 1,dp[i][1] = 1。这是只考虑i节点的情况。

假设当前正在考虑以v为根的子树,那么当前的dp[i][j]表示考虑完i结点和v之前所有的子树后j个领导的数目。

用tmp[j]保存考虑当前子树后j个领导的方案数,计算完v子树后再用tmp更新dp值。

状态转移方程为tmp[j+k] = (tmp[j+k]+dp[v][k]*dp[i][j]*c[siz[i]-cnt][siz[v]]),cnt为v子树之前已经考虑过的节点数目之和,因为要从siz[i]-cnt选出siz[v]个,所以要乘以组合数。

#include<cstdio>#include<cstring>#include<cmath>#include<cstdlib>#include<iostream>#include<algorithm>#include<vector>#include<map>#include<queue>#include<stack>#include<string>#include<map>#include<set>#include<ctime>#define eps 1e-6#define LL long long#define pii pair<int, int>#pragma comment(linker, "/STACK:1024000000,1024000000")using namespace std;const int MAXN = 1100;const int MOD = 1e9 + 7;//const int INF = 0x3f3f3f3f;int n, k;LL dp[MAXN][MAXN], tmp[MAXN];int siz[MAXN];LL c[MAXN][MAXN];vector<int> G[MAXN];void init_c() {c[0][0] = 1;for(int i = 1; i <= 1000; i++) {c[i][0] = 1;for(int j = 1; j <= i; j++) {c[i][j] = c[i-1][j-1]+c[i-1][j];if(c[i][j] >= MOD) c[i][j] -= MOD;}} }void init() {for(int i = 1; i <= n; i++) G[i].clear();memset(dp, 0, sizeof(dp));}void dfs(int cur, int fa) {siz[cur] = 1; for(int i = 0; i < G[cur].size(); i++) {int u = G[cur][i];if(u == fa) continue;dfs(u, cur);siz[cur] += siz[u];}dp[cur][1] = 1;dp[cur][0] = siz[cur] - 1;int cnt = 1;for(int i = 0; i < G[cur].size(); i++) {int u = G[cur][i];if(u == fa) continue;for(int j = 0; j <= cnt+siz[u]; j++) tmp[j] = 0;for(int j = 0; j <= siz[u]; j++) dp[u][j] = (dp[u][j]*c[siz[cur]-cnt][siz[u]]) % MOD;for(int j = 0; j <= cnt; j++) {for(int k = 1; k <= siz[u]; k++) {tmp[j+k] = (tmp[j+k]+dp[u][k]*dp[cur][j]) % MOD;}}cnt += siz[u];for(int j = 0; j <= cnt; j++) dp[cur][j] = tmp[j];}}int main() {    //freopen("input.txt", "r", stdin);int T; cin >> T;int kase = 0;init_c();while(T--) {cin >> n >> k;init();for(int i = 1; i < n; i++) {int u, v;scanf("%d%d", &u, &v);G[u].push_back(v);G[v].push_back(u);}dfs(1, 0);printf("Case #%d: ", ++kase);cout << dp[1][k] << endl;}    return 0;}


0 0
原创粉丝点击