HAOI2010 软件安装 有依赖的背包DP

  

题目描述

现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi。我们希望从中选择一 些软件安装到一台磁盘容量为M计算机上,使得这些软件的价值尽可能大(即Vi的和最大)。

但是现在有个问题:软件之间存在依赖关系,即软件i只有在安装了软件j(包括软件j的直接或间接依赖)的情况下才能正确工作(软件i依赖软件j)。幸运的 是,一个软件最多依赖另外一个软件。如果一个软件不能正常工作,那么它能够发挥的作用为0。

我们现在知道了软件之间的依赖关系:软件i依赖软件Di。现在请你设计出一种方案,安装价值尽量大的软件。一个软件只能被安装一 次,如果一个软件没有依赖则Di=0,这时只要这个软件安装了,它就能正常工作。

输入格式

第1行:N,M (0<=N<=100.0<=M<=500)

第2行:W1,W2,…,Wi,…,Wn(0<=Wi<=M)

第3行:V1,V2,…,Vi,…,Vn(0<=Vi<=1000)

第4行:D1,D2,…,Di,…,Dn(0<=Di<=N,Di≠i)

输出格式

一个整数,代表最大价值。

样例

样例输入

3 10
5 5 6
2 3 4
0 1 1

样例输出

5

  用这个题呢,首先来复习一下背包DP,f[i][v]=max(f[i][v],f[i-1][v-c[i]]+w[i]) 然后发现只从i-1到i转移,直接搞掉第一维,然后调整循环顺序,采用v到0的倒序保证只取一次,然后强一点的背包是完全和多重,完全可以把循环顺序反过来,保证随意取,而多重可以用二进制优化,当然单队也是可以的,这里不再赘述,具体可以参见DD大牛的背包九讲(看了很多遍),那么在简单的分组DP中,保证一个组只取一个或者不去,我们的转移应该这样写;

  for  每一组

    for v...0

      for 每一个元素

        f[i][v]=max(f[i][v],f[i-1][v-c[i]]+w[i];

至于循环顺序,必须将枚举体积套在枚举每一元素的外面,如果放里面其实就和没有组别一样了,不能保证每组只能取一个。

  有依赖的DP就和分组DP很像,我们可以把没有依赖的物品称主件,有依赖的称为附件,本题是在树上,那么一定要定义给以i为根的子树分配V的空间所能达到的最大价值,那然后发现多个儿子转移到父亲似乎不好转移,父亲好像要给儿子分配时间。

  重新考虑一下,对于一个主件对应的几个附件可以看作是决策集合,那么这个集合在子树中有指数级多的的决策,怎么办呢?如果我们优化的话,对于每一个决策,我们要找相同体积找价值最大的,这是显然的,然后从子树转移过来的时候,我们会发现所谓的f[i][v]就是V体积下对应的那个最大的价值,决策已经保证最优,只要循环V转移即可,道理同上。

  别的扯完了,我们可以看一看这个题目,每个物品只有一个出边,仍然可能是基环森林。。。。那么可以通过分析得到,这题取软件不分先后顺序,只要我的依赖取上就行,哪怕是在我后边取,那么一个环共生共灭,然后就可以缩点了,缩点真麻烦,缩完真简便。。。只要在缩完点的森林中建一个虚根0,价值和体积都为0,然后就成了0为根的一棵树,然后这个题就被我们一步一步肢解了。。

  最后说一句,如何保证父亲不取的时候子树均不能做贡献。

  (只要在第二层循环体积的时候只循环到v[x],别的不更新即可。)

  

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
const int N=150,V=550;
vector<int> q[N];
int fr[N],ft[N],s[N],w[N],v[N],size[N],stack[N],du[N],c[N],low[N],vi[N],wi[N],dfn[N],rt=-1,num,cnt,kt,top,n,m,tt,tp,f[N][V];
bool ins[N],b[N];
struct node{int fr,to,pr;}mo[N],no[N];
struct qe{int a,b;};
int rd()
{
    char cc=getchar();
    int s=0,w=1;
    while(cc<‘0‘||cc>‘9‘) {if(cc==‘-‘) w=-1;cc=getchar();}
    while(cc>=‘0‘&&cc<=‘9‘) s=(s<<3)+(s<<1)+cc-‘0‘,cc=getchar();
    return s*w;
}
void init(int x,int y)
{
    no[++tp].fr=x;
    no[tp].to=y;
    no[tp].pr=ft[x];
    ft[x]=tp;du[y]++;
}
void add(int x,int y)
{
    mo[++tt].fr=x;
    mo[tt].to=y;
    mo[tt].pr=fr[x];
    fr[x]=tt;
}
void tarjan(int x)
{
    low[x]=dfn[x]=++num;
    stack[++top]=x;ins[x]=1;
    for(int i=fr[x];i;i=mo[i].pr)
    {
        int y=mo[i].to;
        if(!dfn[y])
        {
            tarjan(y);
            low[x]=min(low[x],low[y]);
        }
        else if(ins[y]) low[x]=min(low[x],dfn[y]);
    }
    if(low[x]==dfn[x])
    {
        int y,s=0;++cnt;
        do{
            y=stack[top--];
            vi[cnt]+=v[y];
            wi[cnt]+=w[y];
            c[y]=cnt;
            ins[y]=0;
        }while(x!=y);
    }
}
void rebuild()
{
    for(int x=1;x<=n;x++)
        for(int i=fr[x];i;i=mo[i].pr)
        {
            int to=mo[i].to;
            if(c[x]!=c[to]) init(c[x],c[to]);
        }
    for(int i=1;i<=cnt;i++)
        if(!du[i]) init(0,i);
}
void dp(int x)
{
    for(int i=m;i>=vi[x];i--) f[x][i]=max(f[x][i],f[x][i-vi[x]]+wi[x]);
    for(int i=ft[x];i;i=no[i].pr)
    {
        int to=no[i].to;
        dp(to);
        for(int i=m;i>=vi[x];i--)
            for(int j=0;j<=i-vi[x];j++)
            f[x][i]=max(f[x][i],f[x][i-j]+f[to][j]);
    }
}
int main()
{
    n=rd();m=rd();
    int x,y,mn=-0x7fffffff;
    for(int i=1;i<=n;i++) v[i]=rd();
    for(int i=1;i<=n;i++) w[i]=rd();
    for(int i=1;i<=n;i++)
    {
        x=rd();
        if(x!=0) add(x,i);
    }
    for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i);
    rebuild();
    dp(0);
    printf("%d\n",f[0][m]);
}
/*
g++ 1.cpp -o 1
./1
4 15
3 2 5 5
3 2 10 7
3 1 2 1
*/

原文地址:https://www.cnblogs.com/starsing/p/11179296.html

时间: 2024-10-12 05:01:26

HAOI2010 软件安装 有依赖的背包DP的相关文章

[Bzoj 2427] [HAOI2010] 软件安装 tarjan缩点+树形DP

题目描述 现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi.我们希望从中选择一 些软件安装到一台磁盘容量为M计算机上,使得这些软件的价值尽可能大(即Vi的和最大). 但是现在有个问题:软件之间存在依赖关系,即软件i只有在安装了软件j(包括软件j的直接或间接依赖)的情况下才能正确工作(软件i依赖软件j).幸运的 是,一个软件最多依赖另外一个软件.如果一个软件不能正常工作,那么它能够发挥的作用为0. 我们现在知道了软件之间的依赖关系:软件i依赖软件Di.现在请你设计出

HAOI2010软件安装(树形背包)

HAOI2010软件安装(树形背包) 题意 有n个物品,每个物品最多会依赖一个物品,但一个物品可以依赖于一个不独立(依赖于其它物品)的物品,且可能有多个物品依赖一个物品,并且依赖关系可能形成一个环.现给你V的资金,问如何分配资金,可以使你的得到的总价值最大,请求出这个总价值. 解法 我以前写过对于普通依赖性背包的博客:noip2006金明的预算方案如果对依赖性背包不是很熟悉的同学可以先看一下这道题. 由于这道题的依赖关系可能形成环,所以我们先用tarjan缩一下点,然后依赖关系图就变成了一个森林

【BZOJ2427】[HAOI2010]软件安装 Tarjan+树形背包

[BZOJ2427][HAOI2010]软件安装 Description 现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi.我们希望从中选择一些软件安装到一台磁盘容量为M计算机上,使得这些软件的价值尽可能大(即Vi的和最大).但是现在有个问题:软件之间存在依赖关系,即软件i只有在安装了软件j(包括软件j的直接或间接依赖)的情况下才能正确工作(软件i依赖软件j).幸运的是,一个软件最多依赖另外一个软件.如果一个软件不能正常工作,那么它能够发挥的作用为0.我们现在知道

BZOJ2427: [HAOI2010]软件安装

2427: [HAOI2010]软件安装 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1512  Solved: 584[Submit][Status][Discuss] Description 现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi.我们希望从中选择一些软件安装到一台磁盘容量为M计算机上,使得这些软件的价值尽可能大(即Vi的和最大). 但是现在有个问题:软件之间存在依赖关系,即软件i只有在安装了软件j

【BZOJ-2427】软件安装 Tarjan + 树形01背包

2427: [HAOI2010]软件安装 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 960  Solved: 380[Submit][Status][Discuss] Description 现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi.我们希望从中选择一些软件安装到一台磁盘容量为M计算机上,使得这些软件的价值尽可能大(即Vi的和最大).但是现在有个问题:软件之间存在依赖关系,即软件i只有在安装了软件j(包

P2515 [HAOI2010]软件安装

P2515 [HAOI2010]软件安装 题目描述 现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi.我们希望从中选择一些软件安装到一台磁盘容量为M计算机上,使得这些软件的价值尽可能大(即Vi的和最大). 但是现在有个问题:软件之间存在依赖关系,即软件i只有在安装了软件j(包括软件j的直接或间接依赖)的情况下才能正确工作(软件i依赖软件j).幸运的是,一个软件最多依赖另外一个软件.如果一个软件不能正常工作,那么它能够发挥的作用为0. 我们现在知道了软件之间的依赖关

BZOJ_2427_[HAOI2010]软件安装_tarjan+树形DP

题意: 现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi.我们希望从中选择一些软件安装到一台磁盘容量为M计算机上,使得这些软件的价值尽可能大(即Vi的和最大). 但是现在有个问题:软件之间存在依赖关系,即软件i只有在安装了软件j(包括软件j的直接或间接依赖)的情况下才能正确工作(软件i依赖软件j).幸运的是,一个软件最多依赖另外一个软件.如果一个软件不能正常工作,那么它能够发挥的作用为0. 我们现在知道了软件之间的依赖关系:软件i依赖软件Di.现在请你设计出一种方

洛谷 P2515 [HAOI2010]软件安装

题目描述 现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi.我们希望从中选择一些软件安装到一台磁盘容量为M计算机上,使得这些软件的价值尽可能大(即Vi的和最大). 但是现在有个问题:软件之间存在依赖关系,即软件i只有在安装了软件j(包括软件j的直接或间接依赖)的情况下才能正确工作(软件i依赖软件j).幸运的是,一个软件最多依赖另外一个软件.如果一个软件不能正常工作,那么它能够发挥的作用为0. 我们现在知道了软件之间的依赖关系:软件i依赖软件Di.现在请你设计出一种

bzoj 2427: [HAOI2010]软件安装

Description 现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi.我们希望从中选择一些软件安装到一台磁盘容量为M计算机上,使得这些软件的价值尽可能大(即Vi的和最大). 但是现在有个问题:软件之间存在依赖关系,即软件i只有在安装了软件j(包括软件j的直接或间接依赖)的情况下才能正确工作(软件i依赖软件j).幸运的是,一个软件最多依赖另外一个软件.如果一个软件不能正常工作,那么它能够发挥的作用为0. 我们现在知道了软件之间的依赖关系:软件i依赖软件Di.现在