CF1453E Dog Snacks
昨天晚上狠狠的被这道题关住了,昨天晚上思考的没有特别仔细,在取最近和最大的问题上想反了。但是大致思路是出来了,其实这题和今年ccpc秦皇岛站的一题很像,都有贪心的策略在里面。
题意:
给定一颗n个节点的树,从一号的出发要最终回到一号点,除了一号点,每个点都只能被访问一次,要做到能走就走,现在求单次步长最大的最小值。
题解:
考虑贪心,假若有一颗全是链的子树的树,肯定是从最长链跑到最短链,留在最短的链的叶子节点,这样的贪心是可以模模可以出来的,此时答案就是最长链+1。此时,向上跳的时候,比较的就是每个相邻子树最小链的值,最优还是向上面一样,从最长跳到最短。特别注意到的是,最后一步,跳回到1节点的时候,是用次长+1和最长比较的。其实可以发现,每个子树保留的信息,就是距离子树中的叶子最近的距离。只有当某个节点的儿子个数大于1时,才会考虑更新答案。还要特判一下,根结点儿子只有一个的情况下。
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 typedef long long ll; 5 6 const int N = 1e6 + 10; 7 typedef pair<ll, ll>PLL; 8 inline int read() 9 { 10 char ch = getchar();int x = 0, f = 1; 11 while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();} 12 while(ch >= '0' && ch <= '9') {x = (x << 1) + (x << 3) - '0' + ch; ch = getchar();} 13 return x * f; 14 } 15 vector<int>g[N]; 16 int n, m, q; 17 int ye[N]; 18 int ans; 19 int cmp(int x, int y) 20 { 21 return ye[x] < ye[y]; 22 } 23 24 void dfs(int u, int fa) { 25 if(g[u].size() == 1 && u != 1) ye[u] = 1; 26 vector<int>tmp; 27 for(int i = 0 ;i < g[u].size();i++) 28 { 29 int v = g[u][i]; 30 if(v == fa) continue; 31 dfs(v, u); 32 // cout << u << " " << ye[u] << '\n'; 33 ye[u] = min(ye[u], ye[v] + 1); 34 tmp.push_back(ye[v]); 35 } 36 sort(tmp.begin(),tmp.end()); 37 if(tmp.size() > 1) 38 { 39 int tt = tmp.size(); 40 // cout << u <<" " << tmp[tt - 1]<<" "<< tmp[tt - 2] + 1<< '\n'; 41 // cout << "!" <<" " <<ye[g[u].back()] << " " << ye[tmp[tt - 2]] << '\n'; 42 if(u == 1) ans = max(ans, max(tmp[tt - 1], tmp[tt - 2] + 1)); 43 else ans = max(ans, tmp.back() + 1); 44 } 45 // cout << ans << '\n'; 46 if(u == 1) ans = max(ans, tmp[0]); 47 } 48 49 50 51 int main() 52 { 53 int t = read(); 54 while(t --) 55 { 56 n = read(); 57 ans = 0; 58 for (int i = 1; i <= n + 10; i ++) 59 { 60 g[i].clear(), ye[i] = N; 61 } 62 for (int i = 1; i <= n - 1; i ++) 63 { 64 int a = read(), b = read(); 65 g[a].push_back(b); 66 g[b].push_back(a); 67 } 68 dfs(1, 0); 69 printf("%d\n", ans); 70 } 71 }