BZOJ 4813
雖然數據范圍很迷人,但是想樹形$dp$沒有前途。
先發現一個事情,就是我們可以先選擇一條鏈,最后要走到這一條鏈上不回來,走到鏈上的點每一個只需要一步,而如果要走這條鏈之外的點,一個點需要走兩步。
這條鏈怎么選取?為了盡量減少步數,肯定是最長鏈。
現在有了一個顯然的事情,如果限制步數$stp$不比最長鏈長度$mx$大的話,那么直接在最長鏈上走一走就好了,答案為$stp + 1$。
一棵樹最少需要$mx + 2 * (n - mx - 1) = 2n - mx - 2$步走完,如果$stp$不小于這個值,那么一定能走完,答案為$n$。
剩下的情況只要先考慮走完最長鏈然后盡量分配步數到別的點上去就好了,答案為$mx + 1 + \left \lfloor \frac{stp - mx}{2} \right \rfloor$。
時間復雜度$O(n)$。
應該也有$dp$的辦法吧。
Code:


#include <cstdio> #include <cstring> using namespace std;const int N = 105;int n, stp, tot = 0, head[N], dep[N];struct Edge {int to, nxt; } e[N << 1];inline void add(int from, int to) {e[++tot].to = to;e[tot].nxt = head[from];head[from] = tot; }inline void read(int &X) {X = 0; char ch = 0; int op = 1;for(; ch > '9' || ch < '0'; ch = getchar())if(ch == '-') op = -1;for(; ch >= '0' && ch <= '9'; ch = getchar())X = (X << 3) + (X << 1) + ch - 48;X *= op; }inline void chkMax(int &x, int y) {if(y > x) x = y; }void dfs(int x, int fat, int depth) {dep[x] = depth;for(int i = head[x]; i; i = e[i].nxt) {int y = e[i].to;if(y == fat) continue;dfs(y, x, depth + 1);} }int main() {read(n), read(stp);for(int x, y, i = 1; i < n; i++) {read(x), read(y);++x, ++y;add(x, y), add(y, x);}dfs(1, 0, 1);int mx = 0;for(int i = 1; i <= n; i++)chkMax(mx, dep[i] - 1);if(stp <= mx) return printf("%d\n", stp + 1), 0;if(stp >= 2 * n - mx - 2) return printf("%d\n", n), 0;printf("%d\n", mx + 1 + (stp - mx) / 2);return 0; }
?