题目
一颗有N+1个结点的树,树中的每个结点可能会生产出一些产品。这些产品要么就地加工(要有加工厂才行),要么运送到它的父亲结点那儿去。现在在整棵树的根结点处已经有了一个产品加工厂,而且所有的产品最终必须在某个加工厂加工才行。由于运费昂贵,不可能将所有的产品都运送到根节点处加工。现在决定在树中的某些结点新增总共K个加工厂,现在要你选择这K个加工厂的厂址。
分析
树形dp,用兄弟孩子表示法,
代码
#include <cstdio>
#include <cctype>
#include <cstring>
using namespace std;
int n,k,w[102],fa[102],d[102],f[102][102][102],bro[102],son[102],dis[102][102];
int in(){
int ans=0; char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=ans*10+c-48,c=getchar();
return ans;
}
int min(int a,int b){return (a<b)?a:b;}
void dp(int x,int limi){
int x1=son[x],x2=bro[x];
for (int i=1;i<=limi;i++) dis[x][i]=dis[fa[x]][i-1]+d[x];
if (x1) dp(x1,limi+1); if (x2) dp(x2,limi);
for (int i=0;i<=n;i++)
for (int j=0;j<=n-i;j++)
for (int p=1;p<=limi;p++)
f[x][i+j][p]=min(f[x][i+j][p],f[x1][i][p+1]+f[x2][j][p]+w[x]*dis[x][p]),
f[x][i+j+1][p]=min(f[x][i+j+1][p],f[x1][i][1]+f[x2][j][p]);
}
int main(){
n=in(); k=in();
for (int i=1;i<=n;i++){
w[i]=in(); fa[i]=in(); d[i]=in();
bro[i]=son[fa[i]]; son[fa[i]]=i;
}
memset(f,0x7f,sizeof(f));
for (int i=0;i<=n;i++)
for (int j=0;j<=n;j++) f[0][i][j]=0;
dp(son[0],1); return !printf("%d",f[son[0]][k][1]);
}