码迷,mamicode.com
首页 > 其他好文 > 详细

p3177 [HAOI2015]树上染色

时间:2019-09-14 16:02:32      阅读:86      评论:0      收藏:0      [点我收藏+]

标签:efi   复杂度   time   复杂   size   cto   cti   ack   转化   

分析

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]树上染色

标签:efi   复杂度   time   复杂   size   cto   cti   ack   转化   

原文地址:https://www.cnblogs.com/yzxverygood/p/11519110.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!