Tarjan+树形DP【洛谷P2515】[HAOI2010]软件安装
【洛谷P2515】[HAOI2010]软件安装
题目描述
现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi。我们希望从中选择一些软件安装到一台磁盘容量为M计算机上,使得这些软件的价值尽可能大(即Vi的和最大)。
但是现在有个问题:软件之间存在依赖关系,即软件i只有在安装了软件j(包括软件j的直接或间接依赖)的情况下才能正确工作(软件i依赖软件j)。幸运的是,一个软件最多依赖另外一个软件。如果一个软件不能正常工作,那么它能够发挥的作用为0。
我们现在知道了软件之间的依赖关系:软件i依赖软件Di。现在请你设计出一种方案,安装价值尽量大的软件。一个软件只能被安装一次,如果一个软件没有依赖则Di=0,这时只要这个软件安装了,它就能正常工作。
Tarjan+树形背包。
Tarjan就是为了恶心人的,注意建边。
模了第一篇题解大佬的奇淫技巧,对于fa是0的点,可以不去管它,等到缩完点重新建边之后,我们统计每个点的入度,如果该点入度为零,那么说明这个点是森林中一棵树的树根,那么这个时候我们再建立超级源点就可以了。
不然的话再所点之前建立超级源点真的恶心,深受其害。。。
至于树形DP,这道题和选课基本上一样,不过我发现了一种更好的有依赖的树形DP的写法,也算是现在才真正学会。
模板:
code:
void dfs(int u){
for(int i=w[u];i<=n;i++)f[u][i]=v[u];
for(int i=head[i];i;i=edge[i].nxt){
int v=edge[i].to;
dfs(v);
for(int j=m;j>=w[u];j--){
for(int k=0;k<=j-w[u];k++){
f[u][j]=max(f[u][j],f[u][j-k]+f[v][k]);
}
}
}
}
code:
#include <iostream>
#include <cstdio>
using namespace std;
const int wx=1017;
inline int read(){
int sum=0,f=1; char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){sum=(sum<<1)+(sum<<3)+ch-'0';ch=getchar();}
return sum*f;
}
int num1,num2,n,m,top,tot,col;
int head1[wx],head2[wx],dfn[wx],low[wx],st[wx];
int belong[wx],f[wx][wx],tmp[wx];
int w[wx],v[wx],W[wx],V[wx],fa[wx];
struct node{
int nxt,to;
}edge1[wx*2];
struct e{
int nxt,to;
}edge2[wx*2];
void add1(int from,int to){
edge1[++num1].nxt=head1[from];
edge1[num1].to=to;
head1[from]=num1;
}
void add2(int from,int to){
edge2[++num2].nxt=head2[from];
edge2[num2].to=to;
head2[from]=num2;
}
void Tarjan(int u){
dfn[u]=low[u]=++tot;
st[++top]=u;
for(int i=head1[u];i;i=edge1[i].nxt){
int v=edge1[i].to;
if(!dfn[v]){
Tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(!belong[v]){
low[u]=min(low[u],dfn[v]);
}
}
if(low[u]==dfn[u]){
belong[u]=++col;
while(st[top]!=u){
belong[st[top]]=col;
top--;
}
top--;
}
}
void CQ(){
for(int i=1;i<=n;i++){
if(belong[i]!=belong[fa[i]]&&fa[i]){
add2(belong[fa[i]],belong[i]);
tmp[belong[i]]++;
}
}
for(int i=1;i<=n;i++){
W[belong[i]]+=w[i];
V[belong[i]]+=v[i];
}
for(int i=1;i<=col;i++){
if(!tmp[i])add2(col+1,i);
}
}
void dfs(int u){
for(int i=W[u];i<=m;i++)f[u][i]=V[u];
for(int i=head2[u];i;i=edge2[i].nxt){
int v=edge2[i].to;
dfs(v);
for(int j=m;j>=W[u];j--){
for(int k=0;k<=j-W[u];k++){
f[u][j]=max(f[u][j],f[u][j-k]+f[v][k]);
}
}
}
}
int main(){
n=read();m=read();
for(int i=1;i<=n;i++)w[i]=read();
for(int i=1;i<=n;i++)v[i]=read();
for(int i=1;i<=n;i++){
fa[i]=read();
if(!fa[i])continue;
add1(fa[i],i);
}
for(int i=1;i<=n;i++)if(!dfn[i])Tarjan(i);
CQ();
dfs(col+1);
printf("%d\n",f[col+1][m]);
return 0;
}
Tarjan+树形DP【洛谷P2515】[HAOI2010]软件安装的更多相关文章
- 洛谷 P2515 [HAOI2010]软件安装 解题报告
P2515 [HAOI2010]软件安装 题目描述 现在我们的手头有\(N\)个软件,对于一个软件\(i\),它要占用\(W_i\)的磁盘空间,它的价值为\(V_i\).我们希望从中选择一些软件安装到 ...
- 洛谷P2515 [HAOI2010]软件安装(tarjan缩点+树形dp)
传送门 我们可以把每一个$d$看做它的父亲,这样这个东西就构成了一个树形结构 问题是他有可能形成环,所以我们还需要一遍tarjan缩点 缩完点后从0向所有入度为零的点连边 然后再跑一下树形dp就行了 ...
- 洛谷 P2515 [HAOI2010]软件安装(缩点+树形dp)
题面 luogu 题解 缩点+树形dp 依赖关系可以看作有向边 因为有环,先缩点 缩点后,有可能图不联通. 我们可以新建一个结点连接每个联通块. 然后就是树形dp了 Code #include< ...
- 洛谷—— P2515 [HAOI2010]软件安装
题目描述 现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi.我们希望从中选择一些软件安装到一台磁盘容量为M计算机上,使得这些软件的价值尽可能大(即Vi的和最大). 但是 ...
- 洛谷 P2515 [HAOI2010]软件安装
题目描述 现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi.我们希望从中选择一些软件安装到一台磁盘容量为M计算机上,使得这些软件的价值尽可能大(即Vi的和最大). 但是 ...
- 洛谷——P2515 [HAOI2010]软件安装
https://www.luogu.org/problem/show?pid=2515#sub 题目描述 现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi.我们希望从中 ...
- 树形DP 洛谷P2014 选课
洛谷P2014 选课 题目描述 在大学里每个学生,为了达到一定的学分,必须从很多课程里选择一些课程来学习,在课程里有些课程必须在某些课程之前学习,如高等数学总是在其它课程之前学习.现在有N门功课,每门 ...
- luogu P2515 [HAOI2010]软件安装 |Tarjan+树上背包
题目描述 现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi.我们希望从中选择一些软件安装到一台磁盘容量为MM计算机上,使得这些软件的价值尽可能大(即Vi的和最大). 但 ...
- [bzoj2427]P2515 [HAOI2010]软件安装(树上背包)
tarjan+树上背包 题目描述 现在我们的手头有 \(N\) 个软件,对于一个软件 \(i\),它要占用 \(W_i\) 的磁盘空间,它的价值为 \(V_i\).我们希望从中选择一些软件安装到一台磁 ...
- P2515 [HAOI2010]软件安装
树形背包 #include<cstdio> #include<cstdlib> #include<algorithm> #include<cstring> ...
随机推荐
- 最新版CocoaPods的安装流程
1.移除现有Ruby默认源 $gem sources --remove https://rubygems.org/ 2.使用新的源 $gem sources -a https://ruby.taoba ...
- 2015.3.12Arinc424 Tools中SiniArincCls.csParserFile(string sFile)函数正则表达式理解
原文: string RegEx1 = @"(\[ITEM\]\s*=[\S\s]*?(?=\[ITEM\])|\[ITEM\]\s*=[\S\s]*)";//用来识别主记录和后续 ...
- 第十六章 Velocity工作原理解析(待续)
Velocity总体架构 JJTree渲染过程解析 事件处理机制 常用优化技巧 与JSP比较 设计模式解析之合成模式 设计模式解析之解释器模式
- Dataguard ORA-19909 ORA-01110
在创建ORACLE 10G Dataguard时,报错: Datafile 1 (ckpscn 24967685451) is orphaned on incarnation#=6 MRP0: Bac ...
- leetcode589
树的先序遍历,使用递归实现. class Solution { public: vector<Node> Tree; void preTree(Node node) { Tree.push ...
- 剑指offer 38_统计数组中k出现的个数
思路: 二分法,分别找出第一个和最后一个k出现的位置.相减 加一 #include <stdio.h> //获取第一个K的位置 int getFirstK (int k,int *numb ...
- 如何取消WIN7的共享密码
如何取消WIN7的共享密码 把你的Guest帐号的密码设为空.如何设置呢? 1.右键“计算机”-“管理”-“本地用户和组”-“用户”-右键帐号“Guest”-“设置密码”,然后直接点击确定,不予设置密 ...
- 使用ffmpeg合并视频
命令: ffmpeg -i concat:"1.avi|2.avi" -vcodec copy -acodec copy "3.avi" ffmpeg下载:ht ...
- C++实现数组的排序/插入重新排序/以及逆置操作
插入新的数字重新排序 分析:将新的数字与已经排序好的数组中的数字一一比较,直到找到插入点,然后将插入点以后的数字都向后移动一个单位(a[i+1]=a[i]),然后将数据插入即可. 代码: #inclu ...
- 使用批处理替换windows系统中的hosts文件
chcp 936 >nul@echo offmode con lines=30 cols=60%1 mshta vbscript:CreateObject("Shell.Applica ...