bzoj 2427
非常好的一道题,可以说是树形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的更多相关文章
- BZOJ 2427 [HAOI2010]软件安装 | 这道树形背包裸题严谨地证明了我的菜
传送门 BZOJ 2427 题解 Tarjan把环缩成点,然后跑树形背包即可. 我用的树形背包是DFS序上搞的那种. 要注意dp数组初始化成-INF! 要注意dp顺推的时候也不要忘记看数组是否越界! ...
- [BZOJ 2427] 软件安装
Link: BZOJ 2427 传送门 Solution: 只看样例的话会以为是裸的树形$dp$…… 但实际上题目并没有说明恰好仅有一个物品没有依赖项 因此原图可能由是由多棵树与多个图组成的 先跑一遍 ...
- bzoj 2427 软件安装 - Tarjan - 树形动态规划
题目描述 现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi.我们希望从中选择一些软件安装到一台磁盘容量为M计算机上,使得这些软件的价值尽可能大(即Vi的和最大). 但是 ...
- BZOJ 2427 & 分块裸题
题意: 求区间内的众数,强制在线. SOL: 推荐一个大神犇的blog,讲的还是很好的(主要我喜欢他的代码风格(逃:http://www.cnblogs.com/JoeFan/p/4248767.ht ...
- BZOJ 2427: [HAOI2010]软件安装( dp )
软件构成了一些树和一些环, 对于环我们要不不选, 要么选整个环. 跑tarjan缩点后, 新建个root, 往每个入度为0的点(强连通分量) 连边, 然后跑树dp( 01背包 ) ---------- ...
- bzoj 2427: [HAOI2010]软件安装
Description 现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi.我们希望从中选择一些软件安装到一台磁盘容量为M计算机上,使得这些软件的价值尽可能大(即Vi的和 ...
- BZOJ 2427 软件安装(强连通分量+树形背包)
题意:现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi.我们希望从中选择一些软件安装到一台磁盘容量为M计算机上,使得这些软件的价值尽可能大(即Vi的和最大).但是现在有 ...
- bzoj 2427 [HAOI2010]软件安装 Tarjan缩点+树形dp
[HAOI2010]软件安装 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 2029 Solved: 811[Submit][Status][Dis ...
- bzoj 2427: [HAOI2010]软件安装【tarjan+树形dp】
一眼最大权闭合子图,然后开始构图,画了画之后发现我其实是个智障网络流满足不了m,于是发现正确的打开方式应该是一眼树上dp 然后仔细看了看性质,发现把依赖关系建成图之后是个奇环森林,这个显然不能直接dp ...
随机推荐
- JSR
JSR是Java Specification Requests的缩写,意思是Java 规范提案.是指向JCP(Java Community Process)提出新增一个标准化技术规范的正式请求.任何人 ...
- TensorFlow学习笔记之--[tf.clip_by_global_norm,tf.clip_by_value,tf.clip_by_norm等的区别]
以下这些函数可以用于解决梯度消失或梯度爆炸问题上. 1. tf.clip_by_value tf.clip_by_value( t, clip_value_min, clip_value_max, n ...
- 原子类型的使用&Unsafe&CAS
在项目中也经常可以见到原子类型(AtomicXXX)的使用,而且AtomicXXX常用来代替基本类型或者基本类型的包装类型,因为其可以在不加同步锁的情况下保证线程安全(只对于原子操作). 下面以Ato ...
- Python笔记 【无序】 【四】
魔法方法1.__xx__ 总是被双下划线包围2.面向对象python的一切 3.能够在适当的时候自动被调用 构造和析构 __init__(self,……) -----相当于构造方法,类在实例 ...
- js学习笔记--基础部分
自增 自增 ++ 通过自增可以使变量在自身的基础上增加1 对于一个变量自增以后,原变量的值会立即自增1 无论使a++, 还是++a,都会立即使原变量的值自增1. 不同的是a++ 和++a的值不同. a ...
- Spring MVC全局异常处理
继承HandlerExceptionResolver接口实现自己的处理方法,如: public class MyHandlerExceptionResolver implements HandlerE ...
- inux下配置rsyncd服务
创建配置文件 touch /etc/rsyncd/rsyncd.conf #主配置文件 touch /etc/rsyncd/rsyncd.secrets #用户名密码文件,一组用户一行,用户名和密码使 ...
- use Swig to create C/C++ extension for Python
SWIG is a software development tool that simplifies the task of interfacing different languages to C ...
- Ex 2_16 给定一个无穷数组..._第二次作业
先比较数组的A[0]元素,若不相等接下来比较A[1],A[2],A[4],A[8]…,若找到一个区间A[2n-1]<x<A[2n],再对这个区间进行折半查找操作.总的时间为O(logn). ...
- appium+java(四)微信公众号自动化测试实践
前言 随着手机阅读的普遍应用,微信公众号阅读,更为普遍,微信和qq一样,都是基于腾讯自研X5内核,不是google原生webview(其实就是进行了二次定制).实质上也是混合应用的一种,现在很多app ...