這題分兩種情況考慮。
1、2*k<=n
這種情況需要中間一段(n-2*k+2長度)是一條直線,直線兩端分別接k-1個點,那麼這k-1個點形成一個星型,只要保證葉子節點比內部節點編號小就滿足情況(直線編號小的那端)。dp搞定。
2、2*k>=n
這個中間一坨需要聯通,然後看成一個球,向外也是星形射出,外面星形的部分和上面一樣,球的部分可以全排列。
我代碼具體做法:枚舉一個點(假設是這個球編號最小的點),然後樹形dp[i][left][right],表示第i個節點爲根的子樹,其中left個節點放前面,right個節點放後面(剩下那些就是球的一部分)。看上去是n^6,複雜度沒那麼高而且n=20
#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <cstring>
using namespace std;
class InducedSubgraphs {
public:
int getCount(vector<int> , vector<int> , int);
};
/////////////////////////////////
long long pmod = 1000000009;
long long C[55][55];
long long ba[55];
void pre() {
int i, j;
for (i = 0; i < 55; ++i) {
C[i][0] = C[i][i] = 1;
for (j = 1; j < i; ++j)
C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % pmod;
}
ba[0] = 1;
for (i = 1; i < 55; ++i)
ba[i] = ba[i - 1] * i % pmod;
}
//////////////////////////////////
int n, k;
vector<int> nt[55];
int path[55];
bool flag1;
int len2;
bool dfs1(int i, int fa, int target, int id) {
path[id] = i;
if (i == target) {
len2 = id + 1;
if (id + 1 != n - 2 * k + 2)
flag1 = false;
for (int j = 1; j < len2 - 1; ++j) {
if (nt[path[j]].size() != 2)
flag1 = false;
}
return true;
}
for (int j = 0; j < nt[i].size(); ++j) {
if (nt[i][j] == fa)
continue;
if (dfs1(nt[i][j], i, target, id + 1))
return true;
}
return false;
}
int cnt[55];
int dfscnt(int i, int fa) {
int ret = 1;
for (int j = 0; j < nt[i].size(); ++j) {
if (nt[i][j] == fa)
continue;
ret += dfscnt(nt[i][j], i);
}
return cnt[i] = ret;
}
long long dfsans(int i, int fa) {
long long ret = 1;
int k = cnt[i] - 1;
for (int j = 0; j < nt[i].size(); ++j) {
if (nt[i][j] == fa)
continue;
ret = ret * C[k][cnt[nt[i][j]]] % pmod;
ret = ret * dfsans(nt[i][j], i) % pmod;
k -= cnt[nt[i][j]];
}
return ret;
}
int gao1() {
long long ans = 0;
int i1, i2;
for (i1 = 0; i1 < n; ++i1) {
for (i2 = 0; i2 < n; ++i2) {
if (i1 == i2)
continue;
flag1 = true;
len2 = 0;
dfs1(i1, -1, i2, 0);
if (!flag1)
continue;
if (dfscnt(i1, path[1]) != k || dfscnt(i2, path[len2 - 2]) != k)
continue;
ans += dfsans(i1, path[1]) * dfsans(i2, path[len2 - 2]) % pmod;
ans %= pmod;
}
}
return ans;
}
int m;
long long dp[50][30][30];
int dfs(int i, int fa) {
int r, s, rr, ss;
int cnt = 1;
dp[i][0][0] = 1;
for (int j = 0; j < nt[i].size(); ++j) {
if (nt[i][j] == fa)
continue;
int k = nt[i][j];
cnt += dfs(k, i);
for (r = m; r >= 0; --r) {
for (s = m; s >= 0; --s) {
if (dp[i][r][s] == 0)
continue;
for (rr = 0; rr + r <= m; ++rr) {
for (ss = 0; ss + s <= m; ++ss) {
if (dp[k][rr][ss] == 0)
continue;
if (rr == 0 && ss == 0)
continue;
dp[i][r + rr][s + ss] += dp[i][r][s] * dp[k][rr][ss]
% pmod * C[r + rr][r] % pmod * C[s + ss][s]
% pmod;
dp[i][r + rr][s + ss] %= pmod;
}
}
}
}
}
dfscnt(i, fa);
long long p = dfsans(i, fa);
if (cnt <= m) {
dp[i][cnt][0] += p;
dp[i][cnt][0] %= pmod;
dp[i][0][cnt] += p;
dp[i][0][cnt] %= pmod;
}
return cnt;
}
int gao2() {
int i;
long long ans = 0;
m = n - k;
for (i = 0; i < n; ++i) {
memset(dp, 0, sizeof(dp));
dfs(i, -1);
ans += dp[i][m][m];
ans %= pmod;
}
return ans * ba[2 * k - n - 1] % pmod;
}
int InducedSubgraphs::getCount(vector<int> edge1, vector<int> edge2, int K) {
int i;
k = K;
n = edge1.size() + 1;
for (i = 0; i < n; ++i)
nt[i].clear();
for (i = 0; i < n - 1; ++i) {
nt[edge1[i]].push_back(edge2[i]);
nt[edge2[i]].push_back(edge1[i]);
}
pre();
if (k == 1)
return ba[n];
if (2 * k <= n)
return gao1();
else
return gao2();
}