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;
}