p3177 [HAOI2015]树上染色

Posted yzxverygood

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了p3177 [HAOI2015]树上染色相关的知识,希望对你有一定的参考价值。

分析

dp[x][i]表示以x为根的子树有i个黑点的方案数

我们发现每次转移要枚举这个点的子树大小和儿子的子树大小

看似复杂度O(n^3)

但是我们可以把循环转化为枚举x子树内的点再枚举它儿子的子树内的点

发现对于一个点它作为儿子子树的点枚举时最多只会和一个点同时枚举到一次

所以总共n^2组点

所以复杂度O(n^2)

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<ctime>
#include<vector>
#include<set>
#include<map>
#include<stack>
using namespace std;
#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define int long long
vector<pair<int,int> >v[2010];
int dp[2010][2010],siz[2010],n,k;
inline void dfs(int x,int fa)
    siz[x]=1;
    for(int _=0;_<v[x].size();_++)
      if(v[x][_].fi!=fa)
          int y=v[x][_].fi,z=v[x][_].se;
          dfs(y,x);
          siz[x]+=siz[y];
      
    memset(dp[x],-1,sizeof(dp[x]));
    dp[x][0]=dp[x][1]=0;
    for(int _=0;_<v[x].size();_++)
      if(v[x][_].fi!=fa)
          int y=v[x][_].fi,z=v[x][_].se;
          for(int i=min(siz[x],k);i>=0;i--)
            for(int j=0;j<=min(siz[y],i);j++)
                if(dp[x][i-j]==-1)continue; 
                int res=j*(k-j)*z+(siz[y]-j)*(n-k-siz[y]+j)*z;
                dp[x][i]=max(dp[x][i],dp[x][i-j]+dp[y][j]+res);
            
      
    return;

signed main()
    int i,j;
    scanf("%lld%lld",&n,&k);
    for(i=1;i<n;i++)
      int x,y,z;
      scanf("%lld%lld%lld",&x,&y,&z);
      v[x].pb(mp(y,z));
      v[y].pb(mp(x,z));
    
    dfs(1,0);
    printf("%lld\n",dp[1][k]);
    return 0;

以上是关于p3177 [HAOI2015]树上染色的主要内容,如果未能解决你的问题,请参考以下文章

P3177 [HAOI2015]树上染色(树形DP)

p3177 [HAOI2015]树上染色

luogu P3177 [HAOI2015]树上染色 |树形DP

[BZOJ4033][HAOI2015]树上染色

BZOJ4033: [HAOI2015]树上染色 树上背包

bzoj 4033: [HAOI2015]树上染色