6
12
2015
0

bzoj 4033: [HAOI2015]T1

这是一类非线性的树形DP问题,首先我们想到F[i][s][j]表示以i为根的子树考虑了S中的儿子有j个黑点的答案

然后我们发现DP起来很有问题因为我们要考虑每一个子树的情况

首先利用背包的性质来进行DP 这样可以少去Sz这一为状态,空间就没有问题了

然后我们发现复杂度是这么一个东西

$$  Sum_x(size[x] * Sum_{y|y是x排在前面的兄弟}size[y])  $$

然后这个东西的复杂度是 $$ O(n^2) $$ 的具体证明不会 但是感受一下二叉树,菊花树,  链什么的都没什么问题

所以就这样了

//coder : davidwang
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
#include <ctime>
using namespace std;
#define LL long long
#define LD long double
#define X first
#define Y second
inline int read()
{
	int ret=0,f=1; char ch;
	for (ch=getchar();ch>'9' || ch<'0';ch=getchar())
		if (ch=='-') f=-f;
	for (;'0'<=ch && ch<='9';ch=getchar())
		ret=ret*10+ch-'0';
	return ret*f;
}
const int N = 2010;
int to[N<<1],next[N<<1],len[N<<1],start[N],cnt,fa[N];
int q[N],size[N],k,n;
inline void connect(int x,int y,int z){
	to[++cnt]=y; next[cnt]=start[x];
	start[x]=cnt; len[cnt]=z;
}
LL f[N][N];
inline LL calc(int x,int i,int y,int j){
	return j * (k - j) + (size[y] - j) * (n - k - (size[y] - j));
}
int main()
{
#ifndef ONLINE_JUDGE
	freopen("a.in","r",stdin);
	freopen("a.out","w",stdout);
#endif
	n=read(); k=read();
	for (int i=1;i<n;i++){
		int x=read(),y=read(),z=read();
		connect(x,y,z);
		connect(y,x,z);
	}
	int head=0,tail=1,u,v;
	q[1]=1;
	memset(fa,-1,sizeof(fa));
	fa[1]=0;
	while (head<tail){
		u=q[++head];
		for (int p=start[u];p;p=next[p]){
			v=to[p];
			if (fa[v]==-1){
				q[++tail]=v;
				fa[v]=u;
			}
		}
	}
	for (int ii=n;ii;ii--){
		int x=q[ii];
		size[x]++;
		f[x][0]=f[x][1]=0;
		for (int p=start[x];p;p=next[p]){
			if (to[p]==fa[x]) continue;
			int y=to[p];
			for (int i=min(k,size[x]);i>=0;i--)
				for (int j=min(size[y],k-i);j>=0;j--)
					f[x][i+j]=max(f[x][i+j],f[x][i]+f[y][j]+calc(x,i,y,j)*len[p]);
			size[x]+=size[y];
		}
	}
	printf("%lld\n",f[1][k]);
}
Category: 未分类 | Tags: bzoj HNOI DP

Host by is-Programmer.com | Power by Chito 1.3.3 beta | Theme: Aeros 2.0 by TheBuckmaker.com