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

 

posted @ 2018-10-04 18:54  Mr_Handsome  阅读(180)  评论(0编辑  收藏  举报