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. linux文件句柄数

    1.问题阐述: too many open files:顾名思义即打开过多文件数. 不过这里的files不单是文件的意思,也包括打开的通讯链接(比如socket),正在监听的端口等等,所以有时候也可以 ...

  2. 基于uFUN开发板的心率计(三)Qt上位机的实现

    前言 上两周利用周末的时间,分别写了基于uFUN开发板的心率计(一)DMA方式获取传感器数据和基于uFUN开发板的心率计(二)动态阈值算法获取心率值,介绍了AD采集传感器数据和数据的滤波处理获取心率值 ...

  3. C#的RSA加密解密签名,就为了支持PEM PKCS#8格式密钥对的导入导出

    差点造了一整个轮子 .Net Framework 4.5 里面的RSA功能,并未提供简单对PEM密钥格式的支持(.Net Core有咩?),差点(还远着)造了一整个轮子,就为了支持PEM PKCS#8 ...

  4. ASS字幕制作

    虽然不常做视频,但正因为是偶尔用到,所以总是记不牢,特此笔记. Name 字体名称?Fontname 字体名称(\fn冬青黑体简体中文 W3)(\fnVogueSans)(例:\N{\fn冬青黑体简体 ...

  5. Session会话与Cookie简单说明

    会话(Session)跟踪是Web程序中常用的技术,用来跟踪用户的整个会话.常用的会话跟踪技术是Cookie与Session.Cookie通过在客户端记录信息确定用户身份,Session通过在服务器端 ...

  6. 毕业设计 之 二 PHP集成环境(Dreamweaver)使用

    毕业设计 之 二 PHP学习笔记(一) 作者:20135216 平台:windows10 软件:XAMPP,DreamWeaver 一.环境搭建 1.XAMPP下载安装 XAMPP是PHP.MySQL ...

  7. Linux内核分析第七周总结

    第七章 可执行程序的装载 可执行程序的生成 可执行程序的生成: c语言代码--->经过编译器的预处理--->编译成汇编代码--->由汇编器编译成目标代码--->链接成可执行文件 ...

  8. jupyter notebook远程配置

    服务器端配置 在服务器生成jupyter配置文件 $jupyter notebook --generate-config 生成之后会得到配置文件的路径 启动jupyter,设置密码 In [1]: f ...

  9. Linux recursively find files

    https://stackoverflow.com/questions/5905054/how-can-i-recursively-find-all-files-in-current-and-subf ...

  10. grep 匹配打印的上下几行

    如果在只是想匹配模式的上下几行,grep可以实现.   $grep -5 'parttern' inputfile //打印匹配行的前后5行   $grep -C 5 'parttern' input ...