树形dp的深入讨论

  越发向dp深入越发现dp越有意思!

  

这道题做的时候感觉十分的难,然后看完学长的题解恍然大悟。设状态不好导致想了一中午,一直感觉不可做,其实是自己的状态设的不对,这道题呢,首先是一个求在树上建多个厂,而也有一道类似的邮箱设置问题,这个则是在坐标轴上设邮局,但那个是四边形不等式优化的区间dp,这个则是一道树形dp了。

先设状态吧,f[i][0/1]表示第i个点建厂不建厂,发现有点问题你不知道距离i点最近的是哪个地方,于是多加一维表示距离最近的一个厂,这时发现还可以设几个厂没有体现出来那0/1发现可以省掉,直接替换,最后f[i][j][k]表示距离i点最近的有厂的j点,此时i点还可设k个厂,这就很显然了~\(^o^)/~

#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<iomanip>
#include<cmath>
#include<ctime>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#include<algorithm>
#define mod 1000007
using namespace std;
inline int read()
{
    int x=0,f=1;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;
}
const int maxn=1000;
int n,k,u=0;
int v[maxn],dis[maxn];
int f[102][102][60];//f[i][j][k]表示对于第i个点距离它最近的厂为点j,其中选择建立了k个厂
int rx[maxn],ls[maxn];//左儿子,右兄弟
int dfs(int x,int root,int k,int d)//x当前节点root距离x最近节点k表示还能再建几个厂d表示积累的距离
{
    if(x==-1)return 0;
    if(f[x][root][k]!=u)return f[x][root][k];
    for(int i=0;i<=k;i++)//如果当前节点不建厂
    {
        int r=dfs(rx[x],root,i,d);
        int l=dfs(ls[x],root,k-i,d+dis[x]);
        int ans=(d+dis[x])*v[x];
        f[x][root][k]=min(f[x][root][k],l+r+ans);
    }
    for(int i=0;i<k;i++)//当前选择建厂
    {
        int r=dfs(rx[x],root,i,d);
        int l=dfs(ls[x],x,k-i-1,0);
        f[x][root][k]=min(f[x][root][k],l+r);
    }
    return f[x][root][k];
}
int main()
{
    //freopen("1.in","r",stdin);
    memset(rx,-1,sizeof(rx));
    memset(ls,-1,sizeof(ls));
    n=read();k=read();
    for(int i=1;i<=n;i++)
    {
        int x;
        v[i]=read();//当前节点生产出来的木块
        x=read();//i节点的父亲
        dis[i]=read();//i到x的距离
        rx[i]=ls[x];ls[x]=i;
    }
    memset(f,10,sizeof(f));
    u=f[0][0][0];
    printf("%d\n",dfs(0,0,k,0));
    return 0;
}

每个人都在追求成功,我呢,快乐就好啊。   ——等一个人咖啡

猜你喜欢

转载自www.cnblogs.com/chdy/p/10050311.html