bzoj4813 [Cqoi2017]小Q的棋盘 树上DP

168 篇文章 0 订阅

题意:一棵树,从上往下走m步,最多能经过多少个不同点。一个点可以重复经过。
n,m<=100.

啊,难得有这么善良的出题人。。。要是是我省的就好了( •̀ ω •́ )y
经典套路题辣,设 f[i][j],g[i][j] 表示从i走j步,不返回/返回的点数。
背包搞搞啦。
f[x][j]=max(f[x][j],f[v][k1]+g[x][jk])
f[x][j]=max(f[x][j],g[v][k2]+f[x][jk])
g[x][j]=max(g[x][j],g[v][k2]+g[x][jk])
注意f的不返回是不返回x,返回到v也算在f的贡献里面。
k-1,k-2分别表示的是儿子的那条边经过一次,两次。这样应该很好理解了。

#include<cstdio>
#include<algorithm>
#include<cstring>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
const int N=1e3+5;
int n,m;
int a[N],b[N],c[N];
int head[N],next[N],go[N],tot;
int f[N][N],g[N][N];
inline void add(int x,int y)
{
    go[++tot]=y;
    next[tot]=head[x];
    head[x]=tot;
}
inline void dfs(int x,int fa)
{
    fo(i,0,m)f[x][i]=g[x][i]=1;
    for(int i=head[x];i;i=next[i])
    {
        int v=go[i];
        if (v!=fa)
        {
            dfs(v,x);
            fd(j,m,0)
                fo(k,1,j)
                {
                    f[x][j]=max(f[x][j],f[v][k-1]+g[x][j-k]);
                    if (k>=2)
                    {
                        f[x][j]=max(f[x][j],g[v][k-2]+f[x][j-k]);   
                        g[x][j]=max(g[x][j],g[v][k-2]+g[x][j-k]);
                    }               
                }
        }
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    fo(i,1,n-1)
    {
        int x,y;
        scanf("%d%d",&x,&y);x++,y++;
        add(x,y);
        add(y,x);
    }
    dfs(1,0);
    printf("%d\n",max(f[1][m],g[1][m]));    
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值