YY_More

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

NOI原题,下了数据,都过了。但是OJ现在挂了。。。

首先,脑袋的数量都是唬人的。如果至少3个脑袋的话,完全可以做到不让两个小头在一起(不过当只有2个头的时候得特别考虑)。

所以我们就把状态设计成F[i][j][k]是以i为根的树里有j个大头吃的果子(k=1时i被大头吃,0时被小头吃)。转移方程很好像,看程序就好了。

我没有转化成二叉树做,其实本质上来说还是树形依赖背包嘛,只不过要讨论父亲节点和儿子节点被那个脑袋吃而已。

//By YY_More
#include<cstdio>
#include<algorithm>
using namespace std;
const int INF=0x7fffffff;
struct edge{
	int point;
	int data;
	edge *next;
};
bool ed[301];
edge *g[301];
int F[2][301][301],num[301],N,M,K,a,b,c;
void insert(int from,int to,int value){
	edge *p=new edge;
	(*p).data=value;
	(*p).point=to;
	(*p).next=g[from];
	g[from]=p;
}	
void cal(int x){
	ed[x]=true;
	edge *p=g[x];
	num[x]=1;
	while (p!=NULL){
		if (!ed[(*p).point]){
			cal((*p).point);
			num[x]+=num[(*p).point];
		}	
		p=(*p).next;
	}
}	
void DP(int x){
	ed[x]=false;
	int now=0,son;
	F[1][x][0]=0;F[0][x][0]=0;
	edge *p=g[x];
	while (p!=NULL){
		if (ed[(*p).point]){
			DP((*p).point);
			son=(*p).point;
			now=min(now,K);
			for (int i=now;i>=0;i--){
				if (i+num[son]<=K){
					F[1][x][i+num[son]]=min(F[1][x][i+num[son]],F[1][x][i]+F[1][son][num[son]]

+(*p).data);
					F[0][x][i+num[son]]=min(F[0][x][i+num[son]],F[0][x][i]+F[1][son][num

[son]]);
				}	
				for (int j=min(K-i,num[son]-1);j>0;j--){
					F[1][x][i+j]=min(F[1][x][i+j],F[1][x][i]+min(F[0][son][j],F[1][son][j]+

(*p).data));
					F[0][x][i+j]=min(F[0][x][i+j],F[0][x][i]+min(F[1][son][j],F[0][son][j]+

(M==2?(*p).data:0)));
				}
				F[1][x][i]=F[1][x][i]+F[0][son][0];
				F[0][x][i]=F[0][x][i]+F[0][son][0]+(M==2?(*p).data:0);
			}	
			now+=min(K,num[son]);
		}
		p=(*p).next;
	}
	for (int i=num[x];i>0;i--) F[1][x][i]=F[1][x][i-1];
}	
int main(){
	scanf("%d%d%d",&N,&M,&K);
	for (int i=2;i<=N;i++){
		scanf("%d%d%d",&a,&b,&c);
		insert(a,b,c);
		insert(b,a,c);
	}
	if (K+M-1>N){
		printf("%d\n",-1);
		return 0;
	}	
	cal(1);		
	fill(&F[0][0][0],&F[1][N][K]+1,INF);
	DP(1);
	printf("%d\n",F[1][1][K]);
	return 0;
}
posted on 2011-07-09 11:23  YY_More  阅读(753)  评论(0编辑  收藏  举报