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;
}
浙公网安备 33010602011771号