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; }