[树形DP][背包]luogu P2515 软件安装

https://www.luogu.org/problemnew/show/P2515

分析

沙雕题*2

这题就是随便做个树形背包,Tarjan缩点把价值和体积加起来而已

注意必须保留当前节点的价值和体积

 

#include <iostream>
#include <cstdio>
#include <memory.h>
using namespace std;
const int N=110;
const int M=510;
struct Graph {
    int u,v,nx;
}g[N*N];
int cnt,list[N],deg[N];
int low[N],dfn[N],tme;
int stk[N],top;
bool instk[N];
int w[N],v[N],idw[N],idv[N],id[N],idcnt;
int n,m,rt;
int f[N][M];

void Add(int u,int v) {
    g[++cnt]=(Graph){u,v,list[u]};list[u]=cnt;
}

void Tarjan(int u) {
    dfn[u]=low[u]=++tme;
    stk[++top]=u;instk[u]=1;
    for (int i=list[u];i;i=g[i].nx)
        if (!dfn[g[i].v]) {
            Tarjan(g[i].v);
            low[u]=min(low[u],low[g[i].v]);
        }
        else if (instk[g[i].v]) low[u]=min(low[u],dfn[g[i].v]);
    if (low[u]==dfn[u])    {
        idcnt++;
        do {
            id[stk[top]]=idcnt;idw[idcnt]+=w[stk[top]];idv[idcnt]+=v[stk[top]];
            instk[stk[top]]=0;
        }
        while (stk[top--]!=u);
    }
}

void DFS(int u) {
    if (idw[u]<=m) f[u][idw[u]]=idv[u];
    for (int i=idw[u]+1;i<=m;i++) f[u][i]=f[u][i-1];
    for (int i=list[u];i;i=g[i].nx) {
        DFS(g[i].v);
        for (int j=m;j>=idw[u];j--)
            for (int k=idw[g[i].v];k<=j-idw[u];k++)
                f[u][j]=max(f[u][j],f[u][j-k]+f[g[i].v][k]);
    }
}

int main() {
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++) scanf("%d",&w[i]);
    for (int i=1;i<=n;i++) scanf("%d",&v[i]);
    for (int i=1,f;i<=n;i++) {
        scanf("%d",&f);
        if (f) Add(f,i);
    }
    for (int i=1;i<=n;i++) if (!dfn[i]) Tarjan(i);
    memset(list,0,sizeof list);cnt=0;
    for (int i=1;i<=m;i++) if (id[g[i].u]!=id[g[i].v]) deg[id[g[i].v]]++,Add(id[g[i].u],id[g[i].v]);
    for (int i=1;i<=idcnt;i++) if (!deg[i]) Add(0,i);
    DFS(0);
    printf("%d",f[0][m]);
}
View Code

 

posted @ 2019-07-09 07:42  Vagari  阅读(163)  评论(0编辑  收藏  举报