【bzoj4033】树上染色 树形dp

AC通道:http://www.lydsy.com/JudgeOnline/problem.php?id=4033

【题解】

用f[i][j]表示以i为根的子树中染了j个黑点的最大收益。

则f[x][j]=max{f[x][j-k]+f[y][k]+temp}

其中temp是该父子边的贡献

#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
#define FILE "read"
#define MAXN 2010
#define INF 1000000000
#define up(i,j,n) for(ll i=j;i<=n;++i)
#define dn(i,j,n) for(ll i=j;i>=n;--i)	
namespace INIT{
	char buf[1<<15],*fs,*ft;
	inline char getc(){return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;}
	inline ll read(){
		ll x=0,f=1;  char ch=getc();
		while(!isdigit(ch))  {if(ch=='-')  f=-1;  ch=getc();}
		while(isdigit(ch))  {x=x*10+ch-'0';  ch=getc();}
		return x*f;
	}
}using namespace INIT;
struct node{ll y,next,v;}e[MAXN*2];
ll n,K,len,Link[MAXN],size[MAXN],f[MAXN][MAXN];
void insert(ll x,ll y,ll v) {e[++len].next=Link[x];Link[x]=len;e[len].y=y;e[len].v=v;}
void dp(ll x,ll fa){
	size[x]=1;  f[x][0]=f[x][1]=0;
	for(ll i=Link[x];i;i=e[i].next){
		if(e[i].y==fa)  continue;
		dp(e[i].y,x);
		size[x]+=size[e[i].y];
		dn(j,size[x],0)  for(ll k=0;k<=size[e[i].y]&&k<=j;++k){
			ll temp=k*(K-k)+(size[e[i].y]-k)*(n-K-(size[e[i].y]-k));
			temp*=e[i].v;  temp+=f[e[i].y][k];
			f[x][j]=max(f[x][j],f[x][j-k]+temp);
		}
	}
}
int main(){
	freopen(FILE".in","r",stdin);
	freopen(FILE".out","w",stdout);
	n=read();  K=read();
	up(i,0,2000)  up(j,0,2000)  f[i][j]=-INF;
	up(i,1,n-1)  {ll x=read(),y=read(),v=read();  insert(x,y,v);  insert(y,x,v);}
	dp(1,0);
	printf("%lld\n",f[1][K]);
	return 0;
}


你可能感兴趣的:(bzoj,树型dp)