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 ...
随机推荐
- 【CentOS】MySQL的安装
版本信息:CentOS 7.2 64位 CentOS(Community Enterprise Operating System,中文意思是:社区企业操作系统)是Linux发行版之一,它是来自于Red ...
- 生成器的throw和close方法
def gen_func(): try: yield 1 except Exception as e: pass yield 2 yield 3 yield 4 yield 5 return &quo ...
- Exception:两个类具有相同的 XML 类型名称,请使用 @XmlType.name 和 @XmlType.namespace 为类分配不同的名称
具体报错: 找到报错的类: 对XmlType重新命名(最简单粗暴的方法):
- Thymeleaf在前台下拉列表获取后台传的值
Thymeleaf在前台下拉列表获取后台传的值 后台添加代码: /** * 新增机构 */ @GetMapping("/add") public String add(ModelM ...
- 【Math for ML】矩阵分解(Matrix Decompositions) (上)
I. 行列式(Determinants)和迹(Trace) 1. 行列式(Determinants) 为避免和绝对值符号混淆,本文一般使用\(det(A)\)来表示矩阵\(A\)的行列式.另外这里的\ ...
- JiBX笔记
注意事项 JiBX:1.2.2 (https://sourceforge.net/projects/jibx/files/jibx/jibx-1.2.2/) JDK:1.6 (http://www.o ...
- mvc5怎么给所有action都设置几个公用的ViewBag
最近开发项目中遇到这样的问题,因为有多个同步的页面,所以需要在多个同步页面上有相同的值返回回来,经过一系列的思维,我们把思维整理出来. public ActionResult Index() { Vi ...
- 【转】MySQL— pymysql and SQLAlchemy
[转]MySQL— pymysql and SQLAlchemy 目录 一.pymysql 二.SQLAlchemy 一.pymysql pymsql是Python中操作MySQL的模块,其使用方法和 ...
- for..of和for..in和map、filter等循环区别
1.for in遍历的是数组的索引(即键名),而for of遍历的是数组元素值. for in遍历比较适合遍历对象,不太适合数组,有可能遍历出来的不按照顺序 遍历数组 ,,,,,] for (var ...
- 51nod--1265 四点共面 (计算几何基础, 点积, 叉积)
题目: 1265 四点共面 基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题 收藏 关注 给出三维空间上的四个点(点与点的位置均不相同),判断这4个点是否在同一个平面内(4 ...