給定一棵 n 個節點的有根樹,邊權為正整數表示距離。從根節點出發,總路徑長度不超過 x,求最多能訪問多少個不同節點(重複經過只算一次)。需回答多組查詢。
定義 d[u][k][c] 表示以 u 為根的子樹中,訪問 k 個節點的最短距離,其中:
c = 0:最終返回 uc = 1:最終不返回 u(即在某子樹中結束)初始狀態:d[u][1][0] = d[u][1][1] = 0(只訪問 u 本身)。
對每個子節點 v(邊長 len),合併 DP 表:
2 * lend[u][j][1] + d[v][k][0] + lend[u][j][0] + d[v][k][1] + 2 * lenconst int MAXN = 550; int d[MAXN][MAXN][2]; int son[MAXN]; vector> g[MAXN]; // {子節點, 邊長} void dfs(int u) { for (int i = 1; i <= n; ++i) d[u][i][0] = d[u][i][1] = INF; d[u][1][0] = d[u][1][1] = 0; son[u] = 1; for (auto [v, len] : g[u]) { dfs(v); for (int j = son[u]; j >= 1; --j) { for (int k = 1; k <= son[v]; ++k) { // 最終返回 u d[u][j+k][0] = min(d[u][j+k][0], d[u][j][0] + d[v][k][0] + 2*len); // 最終不返回 u d[u][j+k][1] = min(d[u][j+k][1], min(d[u][j][0] + d[v][k][1] + len, d[u][j][1] + d[v][k][0] + 2*len)); } } son[u] += son[v]; } }
預處理出根節點的 DP 表後,每個查詢 x 只需掃描 d[root][k][0] ≤ x 的最大 k 即可,時間 O(n) 每查詢。