P2515 [HAOI2010]软件安装

题目描述

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

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

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

输入输出格式

输入格式:

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

第2行:\(W_1,W_2,...W_i,...,W_n\) \((0<=W_i<=M)\)

第3行:\(V_1, V_2, ..., V_i, ..., V_n\) \((0<=V_i<=1000)\)

第4行:\(D_1, D_2, ..., D_i, ..., D_n\) \((0<=D_i<=N, D_i≠i)\)

输出格式:

一个整数,代表最大价值


咋一看十分的像背包,但里面的东西互相拧成一坨相互依赖之类的,我们需要稍微简化一下问题。

一个软件最多依赖另外一个软件,把被别人依赖的某个软件向依赖它的软件连上一条有向边,可以得出,每个点的入度均为1,这是啥?一棵树啊。

然而这样想就出现了问题,万一有环呢?好说,把环给缩掉就行了。我们把新出现的一个森林连上一个共同的虚根0,构成一颗树,于是问题就转换成了树形DP

需要注意的是,一个点要用它子树,当且仅当这个子树的根被选上时才可用。

\(dp[i][j]\)代表以\(i\)为根的树,在容量为\(j\)的时候,没有处理它的根,所得到的最大价值。

转移:\(dp[i][j]=max(dp[i][j],dp[i-k][j]+dp[son][k-w[son]]+v[son])\)


#include <cstdio>
int max(int x,int y){return x>y?x:y;}
int min(int x,int y){return x<y?x:y;}
const int N=104;
const int M=502;
struct Edge
{
int to,next;
}edge[N];
int head[N],cnt=0;
void add(int u,int v)
{
edge[++cnt].next=head[u];edge[cnt].to=v;head[u]=cnt;
}
int n,m,w[N],v[N];
int time=0,low[N],dfn[N],vis[N],s[N],tot=0,ha[N];
int n0=0,w0[N],v0[N],in[N],g[N][N];
void tarjan(int now)
{
low[now]=dfn[now]=++time;
s[++tot]=now;
vis[now]=1;
for(int i=head[now];i;i=edge[i].next)
{
int v=edge[i].to;
if(!dfn[v])
{
tarjan(v);
low[now]=min(low[now],low[v]);
}
else if(vis[v])
low[now]=min(low[now],dfn[v]);
}
if(dfn[now]==low[now])
{
int k;n0++;
do
{
k=s[tot--];
vis[k]=0;
ha[k]=n0;
w0[n0]+=w[k];
v0[n0]+=v[k];
}while(k!=now);
}
}
int dp[N][M];//以i为根(不装)的子树装j时的最大价值
void dfs(int now)
{
for(int i=1;i<=n0;i++)
if(g[now][i])
{
dfs(i);
for(int j=m;j>=w0[i];j--)
for(int k=w0[i];k<=j;k++)
dp[now][j]=max(dp[now][j],dp[i][k-w0[i]]+v0[i]+dp[now][j-k]);
}
}
int main()
{
scanf("%d%d",&n,&m);int to;
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;i<=n;i++) {scanf("%d",&to);if(to) add(to,i);}
for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i);
for(int i=1;i<=n;i++)
for(int j=head[i];j;j=edge[j].next)
{
int v=edge[j].to;
if(ha[i]!=ha[v]&&!g[ha[i]][ha[v]])
g[ha[i]][ha[v]]=1,in[ha[v]]++;
}
for(int i=1;i<=n0;i++)
if(!in[i]) g[0][i]=1;;
dfs(0);
printf("%d\n",dp[0][m]);
return 0;
}

2018.6.13

洛谷 P2515 [HAOI2010]软件安装 解题报告的更多相关文章

  1. 洛谷—— P2515 [HAOI2010]软件安装

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

  2. 洛谷 P2515 [HAOI2010]软件安装

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

  3. 洛谷——P2515 [HAOI2010]软件安装

    https://www.luogu.org/problem/show?pid=2515#sub 题目描述 现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi.我们希望从中 ...

  4. 洛谷 P2515 [HAOI2010]软件安装(缩点+树形dp)

    题面 luogu 题解 缩点+树形dp 依赖关系可以看作有向边 因为有环,先缩点 缩点后,有可能图不联通. 我们可以新建一个结点连接每个联通块. 然后就是树形dp了 Code #include< ...

  5. 洛谷P2515 [HAOI2010]软件安装(tarjan缩点+树形dp)

    传送门 我们可以把每一个$d$看做它的父亲,这样这个东西就构成了一个树形结构 问题是他有可能形成环,所以我们还需要一遍tarjan缩点 缩完点后从0向所有入度为零的点连边 然后再跑一下树形dp就行了 ...

  6. 洛谷_Cx的故事_解题报告_第四题70

    1.并查集求最小生成树 Code: #include <stdio.h> #include <stdlib.h>   struct node {     long x,y,c; ...

  7. 洛谷 P2317 [HNOI2005]星际贸易 解题报告

    P2317 [HNOI2005]星际贸易 题目描述 输入输出格式 输入格式: 输出格式: 如果可以找到这样的方案,那么输出文件output.txt中包含两个整数X和Y.X表示贸易额,Y表示净利润并且两 ...

  8. 洛谷 P3802 小魔女帕琪 解题报告

    P3802 小魔女帕琪 题目背景 从前有一个聪明的小魔女帕琪,兴趣是狩猎吸血鬼. 帕琪能熟练使用七种属性(金.木.水.火.土.日.月)的魔法,除了能使用这么多种属性魔法外,她还能将两种以上属性组合,从 ...

  9. 洛谷 P2606 [ZJOI2010]排列计数 解题报告

    P2606 [ZJOI2010]排列计数 题目描述 称一个\(1,2,...,N\)的排列\(P_1,P_2...,P_n\)是\(Magic\)的,当且仅当对所以的\(2<=i<=N\) ...

随机推荐

  1. EZ 2018 05 20 NOIP2018 模拟赛(十五)

    这次的比赛充满着玄学的气息,玄学链接 首先讲一下为什么没有第十四场 其实今天早上9点时看到题目就叫了:原题! 没错,整套试卷都做过,我还写了题解 然后老叶就说换一套,但如果仅仅是这样就没什么 但等13 ...

  2. [Spark][Python]DataFrame where 操作例子

    [Spark][Python]DataFrame中取出有限个记录的例子 的 继续 [15]: myDF=peopleDF.where("age>21") In [16]: m ...

  3. LDAP学习笔记总结

    一.LDAP概念LDAP是轻量目录访问协议,英文全称是Lightweight Directory Access Protocol,一般都简称为LDAP.它是基于X.500标准的,但是简单多了并且可以根 ...

  4. Git版本控制器使用总结性梳理

    Git为何物?Git 是什么?大家肯定会说不就是版本控制器嘛,是的Git是目前世界上最先进的分布式版本控制系统(没有之一).1)那什么是版本控制器?举个简单的例子,比如我们用Word写文章,那你一定有 ...

  5. Codeforces Round #504 (rated, Div. 1 + Div. 2, based on VK Cup 2018 Final)-D- Array Restoration

    我们知道不满足的肯定是两边大中间小的,这样就用RMQ查询两个相同等值的区间内部最小值即可,注意边界条件 #include<bits/stdc++.h> #define x first #d ...

  6. Week2 代码复查

    代码复查 http://blog.fogcreek.com/increase-defect-detection-with-our-code-review-checklist-example/ 这篇博客 ...

  7. BugPhobia开发篇章:Beta阶段第VIII次Scrum Meeting

    0x01 :Scrum Meeting基本摘要 Beta阶段第八次Scrum Meeting 敏捷开发起始时间 2015/12/22 00:00 A.M. 敏捷开发终止时间 2015/12/22 23 ...

  8. 《Linux内核设计与实现》读书笔记——第四章

    标签(空格分隔): 20135321余佳源 第四章 进程调度 调度程序负责决定将哪个进程投入运行,何时运行以及运行多长时间,进程调度程序可看做在可运行态进程之间分配有限的处理器时间资源的内核子系统. ...

  9. 20135327郭皓--Linux内核分析第八周 进程的切换和系统的一般执行过程

    第八周 进程的切换和系统的一般执行过程 一.进程切换的关键代码switch_to分析 1.进程调度与进程调度的时机分析 不同类型的进程有不同的调度需求 第一种分类: I/O-bound:频繁进行I/O ...

  10. 构建之法--初识Git

    该作业来自于:https://edu.cnblogs.com/campus/gzcc/GZCC-16SE1/homework/2103 GitHub地址:https://github.com/GVic ...