贪吃的九头龙

问题 P(1701): 贪吃的九头龙

时间限制: 2 Sec  内存限制: 128 MB
提交: 57  解决: 22
[提交][状态][我的提交]

题目描述

传说中的九头龙是一种特别贪吃的动物。虽然名字叫“九头龙”,但这只是说它出生的时候有九个头,而在成长的过程中,它有时会长出很多的新头,头的总数会远大于九,当然也会有旧头因衰老而自己脱落。

有一天,有M个脑袋的九头龙看到一棵长有N个果子的果树,喜出望外,恨不得一口把它全部吃掉。可是必须照顾到每个头,因此它需要把N个果子分成M组,每组至少有一个果子,让每个头吃一组。

M个脑袋中有一个最大,称为“大头”,是众头之首,它要吃掉恰好K个果子,而且K个果子中理所当然地应该包括唯一的一个最大的果子果子由N-1根树枝连接起来,由于果树是一个整体,因此可以从任意一个果子出发沿着树枝“走到”任何一个其他的果子。

对于每段树枝,如果它所连接的两个果子需要由不同的头来吃掉,那么两个头会共同把树枝弄断而把果子分开;如果这两个果子是由同一个头来吃掉,那么这个头会懒得把它弄断而直接把果子连同树枝一起吃掉。当然,吃树枝并不是很舒服的,因此每段树枝都有一个吃下去的“难受值”,而九头龙的难受值就是所有头吃掉的树枝的“难受值”之和。

九头龙希望它的“难受值”尽量小,你能帮它算算吗?

例如图1所示的例子中,果树包含8个果子,7段树枝,各段树枝的“难受值”标记在了树枝的旁边。九头龙有两个脑袋,大头需要吃掉4个果子,其中必须包含最大的果子。即N=8M=2K=4

输入

【输入文件】

输入文件dragon.in的第1行包含三个整数N (1<=N<=300)M (2<=M<=N)K (1<=K<=N)。 N个果子依次编号1,2,...,N,且最大的果子的编号总是1。第2行到第N行描述了果树的形态,每行包含三个整数a (1<=a<=N)b (1<=b<=N)c (0<=c<=105),表示存在一段难受值为c的树枝连接果子a和果子b

输出

【输出文件】

输出文件dragon.out仅有一行,包含一个整数,表示在满足“大头”的要求的前提下,九头龙的难受值的最小值。如果无法满足要求,输出-1

样例输入

 (如果复制到控制台无换行,可以先粘贴到文本编辑器,再复制)

8 2 4
1 2 20
1 3 4
1 4 13
2 5 10
2 6 12
3 7 15
3 8 5

样例输出

4

提示

样例对应于题目描述中的例子。

分析:首先,最近嫌疑人x的献身上映~\(≧▽≦)/~啦啦啦,然后虽然我没有时间看,但看到这道题时瞬间想到了石神再监狱里证明四色原理(23333333),然后差不多可以想象,这棵树中,没有三个节点互相相邻的情况,所以一定可以用两种颜色给树染色,让相邻的节点颜色各不同,所以当m>2时只需要考虑大头吃k个果子的消耗,(剩下的小头此时>=2,一定可以0消耗吃完所有果子,就是用两种颜色给树染色,让相邻的节点颜色各不同)m=1时答案为w的和,重点在m=2时,(卡了我好久233333~QnQ~)其实也差不多,m>2时只有父亲被大头吃了,他也被大头吃了时才加当前代价,而m=2,时父亲被大头吃了,他也被大头吃了和父亲没有被大头吃,他也没有被大头吃两种情况都要加上当前代价。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<stack>
#include<algorithm>
#include<vector>
using namespace std;
const int N=300+10;
const int inf=0x3f3f3f3f;
struct bian{
	int v,w,next;
}arr[N<<1];
struct node{
	int l,r;
}tree[N];
void getint(int&num){
    char c;int flag=1;num=0;
    while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
    while(c>='0'&&c<='9'){num=num*10+c-48;c=getchar();}
    num*=flag;
}
int n,m,p,cnt,a,b,w,all,fir[N],A[N],son[N],dp[N][N][2];
bool vis[N][N][2];
void link(int a,int b,int w){
	arr[++cnt].v=a,arr[cnt].w=w;
	arr[cnt].next=fir[b],fir[b]=cnt;
}
void build(int x,int pre){
	int now=0;
	for(int i=fir[x];i;i=arr[i].next)
		if(arr[i].v!=pre){
			A[arr[i].v]=arr[i].w,build(arr[i].v,x);
			if(!tree[x].l)	tree[x].l=arr[i].v,now=arr[i].v;
			else	tree[now].r=arr[i].v,now=arr[i].v;
		}
}
void Son(int x){
	if(!x)	return ;
	Son(tree[x].l),Son(tree[x].r);
	son[x]=son[tree[x].l]+son[tree[x].r]+1;
}
void dfs(int x,int k,bool flag){
	if(vis[x][k][flag])	return ;
	vis[x][k][flag]=1;
	int tmp=inf,add=0;
	if(flag)	add+=A[x];
	if(!k||!x){dp[x][k][flag]=0;return ;}
	if(k==1){
		if(flag)	tmp=min(tmp,A[x]);
		else	tmp=0;
	}
	if(!tree[x].l&&!tree[x].r);
	else if(!tree[x].l){
		if(son[tree[x].r]>=k){
			dfs(tree[x].r,k,flag);
			tmp=min(tmp,dp[tree[x].r][k][flag]);
		}
		if(son[tree[x].r]>=k-1){
			dfs(tree[x].r,k-1,flag);
			tmp=min(tmp,dp[tree[x].r][k-1][flag]+add);
		}
	}
	else if(!tree[x].r){
		if(son[tree[x].l]>=k){
			dfs(tree[x].l,k,0);
			tmp=min(tmp,dp[tree[x].l][k][0]);
		}
		if(son[tree[x].l]>=k-1){
			dfs(tree[x].l,k-1,1);
			tmp=min(tmp,dp[tree[x].l][k-1][1]+add);
		}
	}
	else{
		for(int i=0;i<=k;i++){
			if(son[tree[x].l]<i||son[tree[x].r]<k-i)	continue ;
			dfs(tree[x].l,i,0);
			dfs(tree[x].r,k-i,flag);
			tmp=min(tmp,dp[tree[x].l][i][0]+dp[tree[x].r][k-i][flag]);
		}
		for(int i=1;i<=k;i++){
			if(son[tree[x].l]<i-1||son[tree[x].r]<k-i)	continue ;
			dfs(tree[x].l,i-1,1);
			dfs(tree[x].r,k-i,flag);
			tmp=min(tmp,dp[tree[x].l][i-1][1]+dp[tree[x].r][k-i][flag]+add);
		}
	}
	dp[x][k][flag]=tmp;
}
void work(int x,int k,int flag)
{
    if(vis[x][k][flag])	return ;
	vis[x][k][flag]=1;
    if(!x&&k){dp[x][k][flag]=inf;return ;}
    if(!x&&!k){dp[x][k][flag]=0;return ;}
    int tmp=inf,add=0; 
	if(flag==0)	add=A[x];else	add=0;
    for(int i=0;i<=k;i++){
        work(tree[x].l,i,0),work(tree[x].r,k-i,flag);
        tmp=min(tmp,add+dp[tree[x].l][i][0]+dp[tree[x].r][k-i][flag]);
    }
	if(flag==1)	add=A[x];else	add=0;
    for(int i=0;i<k;i++){
        work(tree[x].l,i,1),work(tree[x].r,k-i-1,flag);
        tmp=min(tmp,add+dp[tree[x].l][i][1]+dp[tree[x].r][k-i-1][flag]);
    }
    dp[x][k][flag]=tmp;
}
int main(){
	getint(n),getint(m),getint(p);
	if(n-p<m-1){
		printf("-1\n");return 0;
	}
	for(int i=1;i<n;i++){
		getint(a),getint(b),getint(w);
		link(a,b,w),link(b,a,w),all+=w;
	}
	if(m==1){
		printf("%d\n",all);return 0;
	}
	build(1,-1),Son(1);
	if(m==2){
		work(tree[1].l,p-1,1);
		printf("%d\n",dp[tree[1].l][p-1][1]);
	}
	else{
		dfs(tree[1].l,p-1,1);
		printf("%d\n",dp[tree[1].l][p-1][1]);
	}
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章