问题 P(1701): 贪吃的九头龙
时间限制: 2 Sec 内存限制: 128 MB提交: 57 解决: 22
[提交][状态][我的提交]
题目描述
传说中的九头龙是一种特别贪吃的动物。虽然名字叫“九头龙”,但这只是说它出生的时候有九个头,而在成长的过程中,它有时会长出很多的新头,头的总数会远大于九,当然也会有旧头因衰老而自己脱落。
有一天,有M个脑袋的九头龙看到一棵长有N个果子的果树,喜出望外,恨不得一口把它全部吃掉。可是必须照顾到每个头,因此它需要把N个果子分成M组,每组至少有一个果子,让每个头吃一组。
这M个脑袋中有一个最大,称为“大头”,是众头之首,它要吃掉恰好K个果子,而且K个果子中理所当然地应该包括唯一的一个最大的果子。果子由N-1根树枝连接起来,由于果树是一个整体,因此可以从任意一个果子出发沿着树枝“走到”任何一个其他的果子。
对于每段树枝,如果它所连接的两个果子需要由不同的头来吃掉,那么两个头会共同把树枝弄断而把果子分开;如果这两个果子是由同一个头来吃掉,那么这个头会懒得把它弄断而直接把果子连同树枝一起吃掉。当然,吃树枝并不是很舒服的,因此每段树枝都有一个吃下去的“难受值”,而九头龙的难受值就是所有头吃掉的树枝的“难受值”之和。
九头龙希望它的“难受值”尽量小,你能帮它算算吗?
例如图1所示的例子中,果树包含8个果子,7段树枝,各段树枝的“难受值”标记在了树枝的旁边。九头龙有两个脑袋,大头需要吃掉4个果子,其中必须包含最大的果子。即N=8,M=2,K=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]);
}
}