【bzoj4813】[Cqoi2017]小Q的棋盘 树上dfs+贪心
题目描述
小Q正在设计一种棋类游戏。在小Q设计的游戏中,棋子可以放在棋盘上的格点中。某些格点之间有连线,棋子只能在有连线的格点之间移动。整个棋盘上共有V个格点,编号为0,1,2…,V-1,它们是连通的,也就是说棋子从任意格点出发,总能到达所有的格点。小Q在设计棋盘时,还保证棋子从一个格点移动到另外任一格点的路径是唯一的。小Q现在想知道,当棋子从格点0出发,移动N步最多能经过多少格点。格点可以重复经过多次,但不重复计数。
输入
第一行包含2个正整数V,N,其中V表示格点总数,N表示移动步数。
接下来V-1行,每行两个数Ai,Bi,表示编号为Ai,Bi的两个格点之间有连线。
V,N≤100, 0 ≤Ai,Bi<V
输出
输出一行一个整数,表示最多经过的格点数量。
样例输入
5 2
1 0
2 1
3 2
4 3
样例输出
3
题解
树上dfs+贪心
先dfs求出以0为起点的最长一条链,这条链上的点只经过一次,消耗1步;其它的点经过后需要返回这条链上,消耗2步。
然后分类讨论是否能走完链和走完树即可。
#include <cstdio> #define N 110 int head[N] , to[N << 1] , next[N << 1] , cnt , deep[N]; void add(int x , int y) { to[++cnt] = y , next[cnt] = head[x] , head[x] = cnt; } void dfs(int x , int fa) { int i; for(i = head[x] ; i ; i = next[i]) if(to[i] != fa) deep[to[i]] = deep[x] + 1 , dfs(to[i] , x); } int main() { int n , p , i , x , y , l = 0; scanf("%d%d" , &n , &p); for(i = 1 ; i < n ; i ++ ) scanf("%d%d" , &x , &y) , add(x , y) , add(y , x); dfs(0 , -1); for(i = 1 ; i < n ; i ++ ) if(l < deep[i]) l = deep[i]; if(p <= l) printf("%d\n" , p + 1); else if(p >= l + 2 * (n - l - 1)) printf("%d\n" , n); else printf("%d\n" , l + (p - l) / 2 + 1); return 0; }