非常好的一道题,可以说是树形dp的一道基础题

首先不难发现,:如果我们把有关系的两个点用有向边相连,那么就会形成一个接近树的结构。如果这是一棵完美的树,我们就可以直接在树上打背包了

但是这并不是一棵完美的树,甚至并不是一棵树,因为:

首先,由于题中有n个点,还有n条边,所以有很大的几率出现环!

而且,如果出现了环,那么很有可能整个图并不连通,这样一来根本无法跑dp

所以我们要采取一些策略:

首先,对于出现环的情况,根据题意,此时环中的所有点要么都选,要么都不选,所以我们可以进行tarjan缩点,然后在新图上进行dp

至于整个图不连通的情况,我们可以虚拟一个超级原点向所有入度为0的点连边,这样就可以形成一棵真正的树,这样跑树形dp就可以了。

#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
using namespace std;
struct Edge
{
int next;
int to;
}edge[105],e[105];
int head[105];
int h[105];
int cot=1;
int cnt=1;
void init()
{
memset(head,-1,sizeof(head));
memset(h,-1,sizeof(h));
cnt=1;
cot=1;
}
void adde(int l,int r)
{
e[cot].next=h[l];
e[cot].to=r;
h[l]=cot++;
}
void add(int l,int r)
{
edge[cnt].next=head[l];
edge[cnt].to=r;
head[l]=cnt++;
}
int n,m;
int w[105];
int v[105];
int nv[105];
int nw[105];
int posi[105];
int src_cnt=0;
int src_num[105];
int my_stack[105];
int dfn[105];
int low[105];
int dp[105][505];
int tot=0;
int ttop=0;
bool used[105];
int s[105];
void tarjan(int rt)
{
my_stack[++ttop]=rt;
dfn[rt]=low[rt]=++tot;
for(int i=head[rt];i!=-1;i=edge[i].next)
{
int to=edge[i].to;
if(!dfn[to])
{
tarjan(to);
low[rt]=min(low[rt],low[to]);
}else if(!posi[to])
{
low[rt]=min(low[rt],dfn[to]);
}
}
if(dfn[rt]==low[rt])
{
int t=0;
src_cnt++;
while(t!=rt)
{
t=my_stack[ttop--];
posi[t]=src_cnt;
src_num[src_cnt]++;
nv[src_cnt]+=v[t];
nw[src_cnt]+=w[t];
}
}
}
void dfs(int x)
{
s[x]=nw[x];
dp[x][nw[x]]=nv[x];
for(int i=h[x];i!=-1;i=e[i].next)
{
int to=e[i].to;
dfs(to);
for(int j=s[x];j>=nw[x];j--)
{
for(int k=0;k<=s[to];k++)
{
if(j+k>m)
{
break;
}
dp[x][j+k]=max(dp[x][j+k],dp[x][j]+dp[to][k]);
}
}
s[x]+=s[to];
}
}
int main()
{
scanf("%d%d",&n,&m);
init();
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++)
{
int f;
scanf("%d",&f);
if(f)
{
add(f,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!=-1;j=edge[j].next)
{
int to=edge[j].to;
if(posi[to]!=posi[i])
{
adde(posi[i],posi[to]);
used[posi[to]]=1;
}
}
}
for(int i=1;i<=src_cnt;i++)
{
if(!used[i])
{
adde(0,i);
}
}
dfs(0);
int ans=0;
for(int i=0;i<=m;i++)
{
ans=max(ans,dp[0][i]);
}
printf("%d\n",ans);
return 0;
}

bzoj 2427的更多相关文章

  1. BZOJ 2427 [HAOI2010]软件安装 | 这道树形背包裸题严谨地证明了我的菜

    传送门 BZOJ 2427 题解 Tarjan把环缩成点,然后跑树形背包即可. 我用的树形背包是DFS序上搞的那种. 要注意dp数组初始化成-INF! 要注意dp顺推的时候也不要忘记看数组是否越界! ...

  2. [BZOJ 2427] 软件安装

    Link: BZOJ 2427 传送门 Solution: 只看样例的话会以为是裸的树形$dp$…… 但实际上题目并没有说明恰好仅有一个物品没有依赖项 因此原图可能由是由多棵树与多个图组成的 先跑一遍 ...

  3. bzoj 2427 软件安装 - Tarjan - 树形动态规划

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

  4. BZOJ 2427 & 分块裸题

    题意: 求区间内的众数,强制在线. SOL: 推荐一个大神犇的blog,讲的还是很好的(主要我喜欢他的代码风格(逃:http://www.cnblogs.com/JoeFan/p/4248767.ht ...

  5. BZOJ 2427: [HAOI2010]软件安装( dp )

    软件构成了一些树和一些环, 对于环我们要不不选, 要么选整个环. 跑tarjan缩点后, 新建个root, 往每个入度为0的点(强连通分量) 连边, 然后跑树dp( 01背包 ) ---------- ...

  6. bzoj 2427: [HAOI2010]软件安装

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

  7. BZOJ 2427 软件安装(强连通分量+树形背包)

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

  8. bzoj 2427 [HAOI2010]软件安装 Tarjan缩点+树形dp

    [HAOI2010]软件安装 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2029  Solved: 811[Submit][Status][Dis ...

  9. bzoj 2427: [HAOI2010]软件安装【tarjan+树形dp】

    一眼最大权闭合子图,然后开始构图,画了画之后发现我其实是个智障网络流满足不了m,于是发现正确的打开方式应该是一眼树上dp 然后仔细看了看性质,发现把依赖关系建成图之后是个奇环森林,这个显然不能直接dp ...

随机推荐

  1. python(四)类变量和实例变量

    转载自[1] 实际这是个实例变量是否指向类变量的问题. python的类变量和实例变量,顾名思义,类变量是指跟类的变量,而实例变量,指跟类的具体实例相关联的变量,具体体现为self.x 等.实际要注意 ...

  2. Struts2-052 漏洞复现

    s2-052漏洞复现 参考链接: http://www.freebuf.com/vuls/147017.html http://www.freebuf.com/vuls/146718.html 漏洞描 ...

  3. 获取AWR报告

    1.进入sqlplus [oracle@localhost admin]$ sqlplus / as sysdba SQL Production :: Copyright (c) , , Oracle ...

  4. C++ std::pair的用法

    1 pair的应用 pair是将2个数据组合成一个数据,当需要这样的需求时就可以使用pair,如stl中的map就是将key和value放在一起来保存.另一个应用是,当一个函数需要返回2个数据的时候, ...

  5. Python3-进程池与线程池

    进程池与线程池 在刚开始学多进程或多线程时,我们迫不及待地基于多进程或多线程实现并发的套接字通信,然而这种实现方式的致命缺陷是:服务的开启的进程数或线程数都会随着并发的客户端数目地增多而增多,这会对服 ...

  6. Go语言中的slice

    Go语言中的slice有点类似于Java中的ArrayList,但在使用上更加灵活,先通过下面一个小例子来体验一下如何通过一个已有的切片来产生一个新切片: func main() { slice := ...

  7. Django:前后端分离后联调给前端传数据

    实现前后端分离后,有了下面几点改变: 1.服务器一分为二,前后端分别部署,静态资源放在前端服务器,业务代码放在后的服务器 2.前端服务器需要接收Http请求(一般使用node.js) 3.前端服务器需 ...

  8. 第六章 MVC之 FileResult和JS请求二进制流文件

    一.FileResult 1.简介 表示一个用于将二进制文件内容发送到响应的基类.它有三个子类: FileContentResultFilePathResultFileStreamResult 推荐阅 ...

  9. webstorm加载项目卡死在scanning files to index

    今天用webstorm导入项目时,需要加载node-modules文件夹,导致webstorm非常卡,页面提示scanning files to index... 网上搜到办法,记录下: 说明: 在n ...

  10. Android Day1

    [2013-10-04 9:49]  复习第一课. Building Your First App; 1.安装好SDK 后,启动Eclipse,新建一个Android工程.设置使用默认. 2.检查文件 ...