P3698 [CQOI2017]小Q的棋盘(树形dp,回与不回)

题目描述:

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

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

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

输入格式

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

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

输出格式

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

输入输出样例

输入 #1
5 2
1 0
2 1
3 2
4 3
输出 #1
3
输入 #2
9 5
0 1
0 2
2 6
4 2
8 1
1 3
3 7
3 5
输出 #2
5
思路:最开始我傻傻得以为点有可能重复,我真的够傻,在哪想半天,一边毫无头绪一边又想提高题怎么可能这么复杂,我真的傻
dp[u][m][2]表示u节点给它m条边,它能访问节点的最大数量,为0表示回到该点,为1表示不回到该点
说白了就是个分组背包,只不过是在dfs回溯的时候加代码罢了
AC代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 105;
struct edge {
    int t, nxt;
}e[maxn << 1];
int hd[maxn], tot;
void add(int f, int t) {
    e[++tot] = { t,hd[f] };
    hd[f] = tot;
}
int n,m;
int dp[maxn][maxn][2];
void dfs(int u, int f,int last) {
    for (int i = 0; i <=last; i++) {
        dp[u][i][0] = dp[u][i][1] = 1;
    }
    if (last == 0)return;
    for (int i = hd[u]; i; i = e[i].nxt) {
        int v = e[i].t;
        if (v == f)continue;
        dfs(v, u,last-1);
        for (int j = last; j >=1; j--) {
            for (int k = j-1; k >=0; k--) {
                //不回来,可以有两种方式松弛,1是走这个孩子回来+走之前的孩子不回来
                //2是走这个孩子不回来+走之前的孩子回来
                //之前做过的题居然忘了还不明所以,我真的是....
                dp[u][j][1] = max(dp[u][j][1], dp[u][j - k - 1][0] + dp[v][k][1]);
                if (j >= k + 2){//回来的情况要多用两条边用来走去儿子和从儿子回到自身
                    dp[u][j][1] = max(dp[u][j][1], dp[u][j - k - 2][1] + dp[v][k][0]);
                    //回来就前面儿子回来+当前儿子回来的最大
                    dp[u][j][0] = max(dp[u][j][0], dp[u][j - k - 2][0] + dp[v][k][0]);
                }
            }
        }
    }
}
int main() {
    //freopen("test.txt", "r", stdin);
    memset(dp, 0xf3, sizeof(dp));
    scanf("%d%d", &n,&m);
    for (int i = 1; i < n; i++) {
        int a, b; scanf("%d%d", &a, &b);
        add(a, b);
        add(b, a);
    }
    dfs(0, -1,m);
    cout <<dp[0][m][1]<< endl;
    return 0;
}

 

 
posted @ 2021-03-23 11:40  cono奇犽哒  阅读(57)  评论(0)    收藏  举报