bzoj 1812

什么鬼noip互测题...

这题很显然是树形dp,但设计状态以及转移是个难点

记状态f[i][j][k]表示以i为根节点的子树,离i最近的祖宗节点编号为j放了虫洞(伐木场?),i的子树内放了k个伐木场的方案数

设to为i的某个子节点,当i不放伐木场时,有:

dp[i][j][k]=min(dp[to][j][k-c]+dp[i][j][c])

当i放伐木场时,有:

dp[i][i][k]=min(dp[to][i][k-c]+dp[i][i]c])

最后合并:

dp[i][j][k]+=num[i]*dis[i][j]

dp[i][j][k]=min(dp[i][j][k],dp[i][i][k])

其中dis[i][j]表示从i到j(j为i的某个祖先节点)的距离,可以预处理出来

特别的,当i为叶节点(即i没有子节点)时,dp[i][j][0]=dis[i][j]*num[i]直接赋值

#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#define ll long long
using namespace std;
int dp[205][205][55];
struct Edge
{
    int next;
    int to;
}edge[205];
int head[205];
int dis[205][205];
int num[205];
int f[205];
int n,k;
int cnt=1;
void init()
{
    memset(head,-1,sizeof(head));
    memset(f,-1,sizeof(f));
    cnt=1;
}
void add(int l,int r)
{
    edge[cnt].next=head[l];
    edge[cnt].to=r;
    head[l]=cnt++;
}
void initdfs(int x)
{
    if(x)
    {
        for(int i=f[x];i!=-1;i=f[i])
        {
            dis[x][i]=dis[x][f[x]]+dis[f[x]][i];
        }
        dis[x][0]=dis[x][f[x]]+dis[f[x]][0];
    }
    for(int i=head[x];i!=-1;i=edge[i].next)
    {
        int to=edge[i].to;
        initdfs(to);
    }
}
void dfs(int x)
{
    if(head[x]==-1)
    {
        for(int i=f[x];i!=-1;i=f[i])
        {
            dp[x][i][0]=dis[x][i]*num[x];
        }
        return;
    }
    if(x)
    {
        dp[x][x][0]=0x3f3f3f3f;
    }
    for(int i=head[x];i!=-1;i=edge[i].next)
    {
        int to=edge[i].to;
        dfs(to);
        for(int j=f[x];j!=-1;j=f[j])
        {
            for(int t=k;t>=0;t--)
            {
                int temp=0x3f3f3f3f;
                for(int c=0;c<=t;c++)
                {
                    temp=min(temp,dp[x][j][c]+dp[to][j][t-c]);
                }
                dp[x][j][t]=temp;
            }
        }
        for(int j=k;j>=0;j--)
        {
            int temp=0x3f3f3f3f;
            for(int c=(x!=0);c<=j;c++)
            {
                temp=min(temp,dp[x][x][c]+dp[to][x][j-c]);
            }
            dp[x][x][j]=temp;
        }
    }
    for(int i=f[x];i!=-1;i=f[i])
    {
        for(int j=0;j<=k;j++)
        {
            dp[x][i][j]+=dis[x][i]*num[x];
            dp[x][i][j]=min(dp[x][i][j],dp[x][x][j]);
        }
    }
}
inline int read()
{
    int f=1,x=0;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
int main()
{
//    freopen("girls.in","r",stdin);
//    freopen("girls.out","w",stdout);
    n=read(),k=read();
    init();
    f[0]=-1;
    for(int i=1;i<=n;i++)
    {
        int v;
        num[i]=read(),f[i]=read(),v=read();
        dis[i][f[i]]=v;
        add(f[i],i);    
    }
    initdfs(0);
    dfs(0);
    printf("%d\n",dp[0][0][k]);
    return 0;
}

 

posted @ 2018-10-08 19:50  lleozhang  Views(71)  Comments(0Edit  收藏  举报
levels of contents