【Luogu P2515】软件安装
Luogu P2515
这道题的题面与P2146有点像。一些不同地方就是P2146是无环的,这题是有环的。
很显然,如果有几个软件的依赖关系形成环,那么这几个软件就可以被看成是一个大软件,其价值和空间都是原先的总和。
那么,我们就可以利用Tarjan算法求强连通分量+缩点,最后加一个树上的背包就可以了。
注意,缩点后的图不一定是一棵树,但是我们可以人为的加入一个权值为零的根节点,连接所有入度为0的点。
有关Tarjan算法和强连通分量:
【Luogu P3387】缩点模板(强连通分量Tarjan&拓扑排序)
#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
const int maxn=110,maxm=510;
int dfn[maxn],low[maxn],stk[maxn],cnt,tim,d[maxn],tot,sccw[maxn],sccv[maxn];
int w[maxn],v[maxn],scc[maxn],in[maxn],ohead[maxn],ocnt,m,n,head[maxn],dp[maxn][maxm],ans;
struct data
{
int to,next;
}oe[maxn],e[maxn];
bool vis[maxn];
void Tarjan(int now)
{
dfn[now]=low[now]=++tim;
stk[++cnt]=now;
vis[now]=true;
for (int i=head[now];i;i=e[i].next)
{
if (!dfn[e[i].to])
{
Tarjan(e[i].to);
low[now]=min(low[now],low[e[i].to]);
}
else
{
if (vis[e[i].to]) low[now]=min(low[now],dfn[e[i].to]);
}
}
if (dfn[now]==low[now])
{
tot++;
while (true)
{
scc[stk[cnt]]=tot;
sccv[tot]+=v[stk[cnt]];
sccw[tot]+=w[stk[cnt]];
vis[stk[cnt]]=false;
cnt--;
if (stk[cnt+1]==now) break;
}
}
}
void dfs(int now)//树上背包
{
//基本思路如下:枚举子树能取的空间,再利用01背包的原理进行状态转移。
//还有一种方法可以把多叉树转化成二叉树,按照左儿子又兄弟的原则重新建树。实现起来比较麻烦,所以没写。
for (int i=sccw[now];i<=m;i++) dp[now][i]=sccv[now];//初始值
for (int i=ohead[now];i;i=oe[i].next)
{
int to=oe[i].to;
dfs(to);
for (int j=m-sccw[now];j>=0;j--)
{
for (int k=0;k<=j;k++)
dp[now][j+sccw[now]]=max(dp[now][j+sccw[now]],dp[now][j+sccw[now]-k]+dp[to][k]);
}
}
}
int main()
{
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",&v[i]);
for (int i=1;i<=n;i++)
{
scanf("%d",&d[i]);
e[i].to=i;
e[i].next=head[d[i]];
head[d[i]]=i;
//注意建边的方向。
}
cnt=0;
for (int i=1;i<=n;i++) if (!dfn[i]) Tarjan(i);
ocnt=0;
for (int i=1;i<=n;i++)
for (int j=head[i];j;j=e[j].next)
if (scc[i]!=scc[e[j].to])
{
oe[++ocnt].to=scc[e[j].to];
oe[ocnt].next=ohead[scc[i]];
ohead[scc[i]]=ocnt;
in[scc[e[j].to]]++;//统计入度
}
tot++;//人为加入的根节点
for (int i=1;i<tot;i++)
if (in[i]==0)
{
oe[++ocnt].to=i;
oe[ocnt].next=ohead[tot];
ohead[tot]=ocnt;//连边。
}
dfs(tot);
printf("%d\n",dp[tot][m]);
return 0;
}
【Luogu P2515】软件安装的更多相关文章
- Libre 6009 「网络流 24 题」软件补丁 / Luogu 2761 软件安装问题 (最短路径,位运算)
Libre 6009 「网络流 24 题」软件补丁 / Luogu 2761 软件安装问题 (最短路径,位运算) Description T 公司发现其研制的一个软件中有 n 个错误,随即为该软件发放 ...
- 【Luogu】P2515软件安装(树形DP)
题目链接 这么水的题我一遍没A,而且前两次提交都只有十分.气死我了.本来我的博客拒收水题来着. Tarjan缩点之后跑树形DP即可. #include<cstdio> #include&l ...
- luogu P2515 [HAOI2010]软件安装 |Tarjan+树上背包
题目描述 现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi.我们希望从中选择一些软件安装到一台磁盘容量为MM计算机上,使得这些软件的价值尽可能大(即Vi的和最大). 但 ...
- 洛谷 P2515 [HAOI2010]软件安装 解题报告
P2515 [HAOI2010]软件安装 题目描述 现在我们的手头有\(N\)个软件,对于一个软件\(i\),它要占用\(W_i\)的磁盘空间,它的价值为\(V_i\).我们希望从中选择一些软件安装到 ...
- Tarjan+树形DP【洛谷P2515】[HAOI2010]软件安装
[洛谷P2515][HAOI2010]软件安装 题目描述 现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi.我们希望从中选择一些软件安装到一台磁盘容量为M计算机上,使得 ...
- 洛谷——P2515 [HAOI2010]软件安装
https://www.luogu.org/problem/show?pid=2515#sub 题目描述 现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi.我们希望从中 ...
- 【洛谷P2515【HAOI2010】】软件安装
题目描述 现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi.我们希望从中选择一些软件安装到一台磁盘容量为M计算机上,使得这些软件的价值尽可能大(即Vi的和最大). 但是 ...
- 洛谷—— P2515 [HAOI2010]软件安装
题目描述 现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi.我们希望从中选择一些软件安装到一台磁盘容量为M计算机上,使得这些软件的价值尽可能大(即Vi的和最大). 但是 ...
- 洛谷 P2515 [HAOI2010]软件安装
题目描述 现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi.我们希望从中选择一些软件安装到一台磁盘容量为M计算机上,使得这些软件的价值尽可能大(即Vi的和最大). 但是 ...
随机推荐
- Java HashMap底层实现原理源码分析Jdk8
在JDK1.6,JDK1.7中,HashMap采用位桶+链表实现,即使用链表处理冲突,同一hash值的链表都存储在一个链表里.但是当位于一个桶中的元素较多,即hash值相等的元素较多时,通过key值依 ...
- Ubuntu 16 server 安装 tensorflow-GPU
目录 显卡驱动安装 CUDA安装 cuDNN安装 tensorflow-gpu安装 本次使用主机配置: cpu:i7-8700K 显卡:GTX-1080Ti 一.安装显卡驱动 打开命令窗口(c ...
- 第一篇:版本控制git之仓库管理
---恢复内容开始--- 再开始这个话题之前,让我想起了一件很痛苦的事情,在我大学写毕业论文的时候,我当时的文件是这样保存的 毕业论文_初稿.doc 毕业论文_修改1.doc 毕业论文_修改2.doc ...
- Flask:数据库的建模
学习完模板系统,接下来要研究的就是框架对数据库的操作,不论python的那个框架,直接使用数据库API(redis.pymysql等)都可以进行操作,但是这些操作不够方便,于是就有了ORM 1.Fla ...
- js垃圾回收
内存生命周期 分配你所需要的内存 使用分配到的内存(读.写) 不需要时将其释放\归还 所有语言第二部分都是明确的.第一和第三部分在底层语言中是明确的,但在像 JavaScript 这些高级语言中,嵌入 ...
- 暑期集训20190726 跳动(skip)
[题目描述] 福州三中的操场上有着数不尽的跳动的小朋友. 当然善于思考的你总能从中发掘出不一样的问题 福州三中的跑道是一个n个格子围成的圆形,从0~n-1编号,有m个同学,第i个同学步长为a[i], ...
- Java 干货之深入理解Java泛型
一般的类和方法,只能使用具体的类型,要么是基本类型,要么是自定义的类.如果要编写可以应用多中类型的代码,这种刻板的限制对代码得束缚会就会很大. ---<Thinking in Java> ...
- C#中的取整函数
先放百度的 Math.Ceiling();向上取整 Math.Ceiling()向上取整: d = 4.56789 string res = Math.Ceiling(Convert.ToDecima ...
- python中字典的基础操作
dict1 = { 'name':'王麻子', 'age':25, 'phone':12580, 'high':160 } dict2 = { 'name':'张三', 'age':38, 'phon ...
- Linux中文件的SUID、SGID、Sticky权限说明
1.SUID 首先我们要了解,在Linux中启动一个程序或者启动一个进程是需要有用户的,一个文件的存在是要有用户和组的,一个进程启动后,它的属主取决于进程的发起者,比如 我用root用户启动了一个 c ...