【洛谷luogu】P3360-偷天换日(树形DP)

原题链接:https://www.luogu.org/problemnew/show/P3360

题目大意

给一个有根树,有边权,叶子节点有画可以偷,偷画和经过边需要时间,给定n时间,最多可以偷多少价值的画。

解法

这奇怪的数据格式真是给跪了,叶子节点可以背包,非叶子节点怎么办呢?暴力枚举!

#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define forn(i, n) for (int i = 0; i < (int)(n); ++i)
#define for1(i, n) for (int i = 1; i <= (int)(n); ++i)
#define pb push_back

using namespace std;
typedef long long LL;
const int N=1000+5;
struct Node{
    int lchild,rchild,w,x;
}Tree[N];
int cnt=0;
int New(int w,int x){
    Tree[++cnt].w=w;
    Tree[cnt].x=x;
    Tree[cnt].lchild=-1;
    Tree[cnt].rchild=-1;
    return cnt;
}
int dp[300+5][30+5][600+5];
int Build(){
    int t,x,w,c;
    cin>>t>>x;
    int r=New(t,x);
    if(x>0){
        //dp[300][30][600]
    //	cout<<"r is "<
        for(int i=1;i<=x;i++){
            cin>>w>>c;
            for(int j=1;j<=600;j++){
                if(j>=c) dp[r][i][j]=max(dp[r][i-1][j],dp[r][i-1][j-c]+w);
                else dp[r][i][j]=dp[r][i-1][j];
            //	cout<
            }
    //		cout<
        }
    //	cout<
    }
    else if(x==0){
        Tree[r].lchild=Build();
        Tree[r].rchild=Build();
    }
    return r;
}

void dfs(int u){
    if(Tree[u].x>0) return ;
    int l=Tree[u].lchild;
    int r=Tree[u].rchild;
    dfs(l);
    dfs(r);
    int lx=(Tree[l].x>0?Tree[l].x:2);
    int rx=(Tree[r].x>0?Tree[r].x:2);
    int lw=Tree[l].w;
    int rw=Tree[r].w;
    for(int i=0;i<=600;i++){
        for(int j=0;j+i<=600;j++){
            dp[u][2][i+j]=max(dp[u][2][i+j],(i-2*lw>=0?dp[l][lx][i-2*lw]:0)+(j-2*rw>=0?dp[r][rx][j-2*rw]:0));
        }
    }
}


int main() {

#ifdef LOCAL_DEFINE
    freopen("input.in", "rt", stdin);
#endif
    int n;
    cin>>n;
    int r=Build();
    dfs(r);
    int rw=Tree[r].w;
    cout<<dp[r][2][n-2*rw-1]<<endl;

#ifdef LOCAL_DEFINE
    cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
    return 0;
}

你可能感兴趣的:(算法与数据结构)