[HAOI 2010] 软件安装

题目描述:

QAQ…

题目分析:

有依赖性关系的背包问题称为树形依赖背包…
用树形动归的方法解决
转移方程并不难
dp[i][j]表示以i为根的子树背包容量为j所能达到的最大价值
实际操作中我们可以用一个虚根来链接没有依赖的点…
这样的转移是 n m 2
听说黑科技可以做到 n m

for(int i=w[now];i<=m;i++) dp[now][i]=val[now];
for(int i=head[now];i;i=net[i])
    {
        dfs(to[i]);
        for(int j=m-w[now];j>=0;j--) 
         for(int k=0;k<=j;k++)
          dp[now][j+w[now]]=std::max(dp[now][j+w[now]],dp[now][j+w[now]-k]+dp[to[i]][k]);
    }

要注意一个问题,当依赖关系形成环的时候,我们只能将环内的点全部选了,或者是全部不选,所以需要用Tarjan先缩一下点…

题目链接:

BZOJ 2427
Luogu 2515
COGS 444

Ac 代码:

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <iostream>
const int maxm=1001; 
int dp[maxm][501],d[maxm];
int dfn[maxm],low[maxm],vis[maxm],c[maxm],stk[maxm],num,col,top;
int W[maxm],Val[maxm],val[maxm],w[maxm],fa[maxm];
int _head[maxm],_to[maxm<<1],_net[maxm<<1],_cnt;
int head[maxm],to[maxm<<1],net[maxm<<1],cnt;
int n,m;
inline void addedge(int u,int v)
{
    cnt++;
    to[cnt]=v,net[cnt]=head[u],head[u]=cnt;
}
inline void _addedge(int u,int v)
{
    _cnt++;
    _to[_cnt]=v,_net[_cnt]=_head[u],_head[u]=_cnt;
} 
void Tarjan(int x)
{
    dfn[x]=low[x]=++num;
    stk[++top]=x;
    vis[x]=1;
    for(int i=_head[x];i;i=_net[i])
    {
        int p=_to[i];
        if(!dfn[p])
        {
            Tarjan(p);
            low[x]=std::min(low[x],low[p]);
        }
        else if(vis[p]) low[x]=std::min(low[x],dfn[p]);
    }
    if(low[x]==dfn[x])
    {
        col++;
        while(stk[top]!=x)
        {
            c[stk[top]]=col;
            vis[stk[top--]]=0;
        }
        c[x]=col,vis[x]=0;
        top--;
    }
}
void dfs(int now)
{
    for(int i=w[now];i<=m;i++) dp[now][i]=val[now];
    for(int i=head[now];i;i=net[i])
    {
        dfs(to[i]);
        for(int j=m-w[now];j>=0;j--) 
         for(int k=0;k<=j;k++)
          dp[now][j+w[now]]=std::max(dp[now][j+w[now]],dp[now][j+w[now]-k]+dp[to[i]][k]);
    }
}
int main()
{
    //freopen("install.in","r",stdin);
    //freopen("install.out","w",stdout);
    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",&Val[i]);
    for(int i=1,x;i<=n;i++)
    {
        scanf("%d",&fa[i]);
        if(fa[i]) _addedge(fa[i],i);
    }
    for(int i=1;i<=n;i++) if(!dfn[i]) Tarjan(i);
    for(int i=1;i<=n;i++) 
    {
        if(c[i]!=c[fa[i]]) addedge(c[fa[i]],c[i]),d[c[i]]++;
        w[c[i]]+=W[i];
        val[c[i]]+=Val[i];
    }
    for(int i=1;i<=col;i++) if(!d[i]) addedge(0,i); 
    dfs(0);
    printf("%d\n",dp[0][m]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_35914587/article/details/80240614
今日推荐