BZOJ 1813 [Cqoi2017]小Q的棋盘 ——树形DP

唔,貌似以前做过这样差不多的题目。

用$f(i,0/1)$表示从某一点出发,只能走子树的情况下回到根、不回到根的最多经过不同的点数。

然后就可以DP辣

#include <map>
#include <cmath>
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define F(i,j,k) for (int i=j;i<=k;++i)
#define D(i,j,k) for (int i=j;i>=k;--i)
#define ll long long
#define mp make_pair
 
int dp[105][105][2],n,m;
int h[205],to[205],ne[205],en=0;
 
void add(int a,int b)
{to[en]=b;ne[en]=h[a];h[a]=en++;}
 
void Finout()
{
    freopen("chessboard.in","r",stdin);
    freopen("chessboard.out","w",stdout);
}
 
void dfs(int o,int fa)
{
    dp[o][0][1]=1;
    for (int i=h[o];i>=0;i=ne[i])
        if (to[i]!=fa)
        {
            dfs(to[i],o);
            for (int j=m;j>=0;--j)
            {
                for (int k=0;k<=j-2;++k)
                    dp[o][j][1]=max(dp[o][j][1],dp[to[i]][k][1]+dp[o][j-k-2][1]);
                for (int k=0;k<=j-2;++k)
                    dp[o][j][0]=max(dp[o][j][0],dp[to[i]][k][1]+dp[o][j-k-2][0]);
                for (int k=0;k<=j-1;++k)
                    dp[o][j][0]=max(dp[o][j][0],dp[to[i]][k][0]+dp[o][j-k-1][1]);
            }
        }
    for (int j=m;j>=0;--j)
        dp[o][j][0]=max(dp[o][j][0],dp[o][j][1]);
}
 
int main()
{
    memset(dp,-0x3f,sizeof dp);
    memset(h,-1,sizeof h);
    scanf("%d%d",&n,&m);
    F(i,1,n-1)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        a++;b++;add(a,b);add(b,a);
    }
    dfs(1,-1);
    int ans=-1;
    F(i,0,m) ans=max(ans,max(dp[1][i][0],dp[1][i][1]));
    printf("%d\n",ans);
}

  

posted @ 2017-04-20 08:42  SfailSth  阅读(140)  评论(0编辑  收藏  举报