P3698 [CQOI2017]小Q的棋盘

$ \color{#0066ff}{ 题目描述 }$

小 Q 正在设计一种棋类游戏。

在小 Q 设计的游戏中,棋子可以放在棋盘上的格点中。某些格点之间有连线,棋子只能在有连线的格点之间移动。整个棋盘上共有 V 个格点,编号为0,1,2 … , V− 1,它们是连通的,也就是说棋子从任意格点出发,总能到达所有的格点。小 Q 在设计棋盘时,还保证棋子从一个格点移动到另外任一格点的路径是唯一的。

小 Q 现在想知道,当棋子从格点 0 出发,移动 N 步最多能经过多少格点。格点可以重复经过多次,但不重复计数。

\(\color{#0066ff}{输入格式}\)

第一行包含2个正整数V, N,其中 V 表示格点总数,N 表示移动步数。

接下来V − 1行,每行两个数\(a_i,b_i\),表示编号为\(a_i,b_i\)的两个格点之间有连线。

\(\color{#0066ff}{输出格式}\)

输出一行一个整数,表示最多经过的格点数量。

\(\color{#0066ff}{输入样例}\)

5 2
1 0
2 1
3 2
4 3
    

    
    
9 5
0 1
0 2
2 6
4 2
8 1
1 3
3 7
3 5

\(\color{#0066ff}{输出样例}\)

3
    
    
5

\(\color{#0066ff}{数据范围与提示}\)

【输入输出样例 1 说明】

从格点 0 出发移动 2 步。经过 0, 1, 2 这 3 个格点。

【输入输出样例 2 说明】

一种可行的移动路径为 0 → 1 → 3 → 5 → 3 → 7,经过 0, 1, 3, 5, 7 这 5 个格点。

【数据规模与约定】

对于 100%的测试点,N,V ≤ 100, \(0 ≤a_i,b_i< V\)

\(\color{#0066ff}{题解}\)

显然是个树形DP,然而我并不会。。

考虑贪心qwq

因为我们并不用回来,所以肯定是走一条最长链+一堆分支

走分支走过去再回到主链上,所以答案就是最长链+(剩下的部分的一半)

#include<bits/stdc++.h>
#define LL long long
LL in() {
    char ch; LL x = 0, f = 1;
    while(!isdigit(ch = getchar()))(ch == '-') && (f = -f);
    for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 1) + (x << 3) + (ch ^ 48));
    return x * f;
}
const int maxn = 1e5 + 10;
struct node {
    int to;
    node *nxt;
    node(int to = 0, node *nxt = NULL): to(to), nxt(nxt) {}
};
node *head[maxn];
bool vis[maxn];
int n, m, max;
void add(int from, int to) { head[from] = new node(to, head[from]); }
void dfs(int x, int fa, int dep) {
    max = std::max(max, dep);
    for(node *i = head[x]; i; i = i->nxt) 
        if(i->to != fa) 
            dfs(i->to, x, dep + 1);
}
int main() {
    n = in(), m = in();
    int x, y;
    for(int i = 1; i < n; i++) x = in() + 1, y = in() + 1, add(x, y), add(y, x);
    dfs(1, 0, 1);
    if(m + 1 > max) printf("%d\n", std::min(n, max + ((m - max + 1) >> 1)));
    else printf("%d\n", m + 1);
    return 0;
}
posted @ 2019-03-30 14:01  olinr  阅读(198)  评论(0编辑  收藏  举报