bzoj1812 riv(树形背包)
dp[i][j][k]表枚举到第i个节点,以该结点为根的子树中建了k个伐木场,距离i最近的伐木场是j的最小距离
有一些细节。。。
代码:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; int n,m,cnt; int head[205]; int fa[205]; int val[205]; int dis[205][205]; int dp[205][205][55]; struct Edge{ int to; int nxt; }edge[205]; void init(){ memset(head,-1,sizeof(head)); memset(fa,-1,sizeof(fa)); } void addedge(int f,int t){ cnt++; edge[cnt].to=t; edge[cnt].nxt=head[f]; head[f]=cnt; } void DFS(int p){ int la=p; for(int i=fa[p];i!=-1;i=fa[i]){ dis[p][i]=dis[p][la]+dis[la][i]; la=i; } if(head[p]==-1){ for(int i=fa[p];i!=-1;i=fa[i]){ dp[p][i][0]=dis[p][i]*val[p]; } return; } if(p)dp[p][p][0]=0x3f3f3f3f; for(int i=head[p];i!=-1;i=edge[i].nxt){ int e=edge[i].to; DFS(e); for(int f=fa[p];f!=-1;f=fa[f]){ for(int j=m;j>=0;j--){ int tmp=0x3f3f3f3f; for(int k=0;k<=j;k++){ tmp=min(tmp,dp[p][f][k]+dp[e][f][j-k]); } dp[p][f][j]=tmp; } } for(int j=m;j>=0;j--){ int tmp=0x3f3f3f3f; for(int k=(p!=0);k<=j;k++){ tmp=min(tmp,dp[p][p][k]+dp[e][p][j-k]); } dp[p][p][j]=tmp; } } for(int i=fa[p];i!=-1;i=fa[i]){ for(int j=0;j<=m;j++){ dp[p][i][j]+=dis[p][i]*val[p]; dp[p][i][j]=min(dp[p][i][j],dp[p][p][j]); } } } int main(){ freopen("girls.in","r",stdin); freopen("girls.out","w",stdout); init(); scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ int w; scanf("%d%d%d",&val[i],&fa[i],&w); addedge(fa[i],i); dis[i][fa[i]]=w; } DFS(0); printf("%d\n",dp[0][0][m]); return 0; }