博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[Bzoj 2427] [HAOI2010] 软件安装 tarjan缩点+树形DP
阅读量:5113 次
发布时间:2019-06-13

本文共 2527 字,大约阅读时间需要 8 分钟。

题目描述

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

但是现在有个问题:软件之间存在依赖关系,即软件i只有在安装了软件j(包括软件j的直接或间接依赖)的情况下才能正确工作(软件i依赖软件j)。幸运的 是,一个软件最多依赖另外一个软件。如果一个软件不能正常工作,那么它能够发挥的作用为0。

我们现在知道了软件之间的依赖关系:软件i依赖软件Di。现在请你设计出一种方案,安装价值尽量大的软件。一个软件只能被安装一 次,如果一个软件没有依赖则Di=0,这时只要这个软件安装了,它就能正常工作。

输入格式

第1行:N,M (0<=N<=100.0<=M<=500)

第2行:W1,W2,…,Wi,…,Wn(0<=Wi<=M)

第3行:V1,V2,…,Vi,…,Vn(0<=Vi<=1000)

第4行:D1,D2,…,Di,…,Dn(0<=Di<=N,Di≠i)

输出格式

一个整数,代表最大价值。

样例

样例输入

3 105 5 62 3 40 1 1

样例输出

5

solution

注意一下这个,这道题没有说不能有环。。。所以我们要用到简单易懂(够你调一年)的tarjan缩点。

环的情况是存在的,如果存在一个依赖的环,我们要想安装其中一个软件的话就是把环上所有软件都一起打包安装(其实就是缩点)(不要跟我说你不能同时安装几个软件

刚看到这题就想起了金明那道题:

但这题还是有些不一样的

一开始想用dfs序,但始终做不出来,还是乖乖去搞树形dp了

我们先用tarjan找强联通分量,处理出新的w和v

之后在用求出来的强联通分量建图。建出来的图可能会是一片森林,所以我们搞一个虚拟的点,连接所有树的根节点;

这样就可以愉快地在新树上做树形依赖背包了,f[i][j]表示以i为根节点的子树占用j的空间所能得到的最大价值,目标f[root][M]。

 

#include
#include
#include
#include
using namespace std;const int MAXN=105;const int MAXM=505;int n,m,w[MAXN],v[MAXN],d[MAXN];int ver[MAXN],first[MAXN],head[MAXN],cnt=0;void add(int u,int v){ cnt++,ver[cnt]=v,head[cnt]=first[u],first[u]=cnt;}int dfn[MAXN],low[MAXN],belong[MAXN],dfs_num=0,stack[MAXN],top=0;int W[MAXN],V[MAXN],tot=0;bool in_stack[MAXN];void tarjan(int x){ dfn[x]=low[x]=++dfs_num; in_stack[x]=1; stack[++top]=x; for(int i=first[x];i;i=head[i]){ int v=ver[i]; if(!dfn[v]){ tarjan(v); low[x]=min(low[x],low[v]); } else if(in_stack[v]){ low[x]=min(low[x],dfn[v]); } } if(dfn[x]==low[x]){ tot++; int y; do{ y=stack[top--]; in_stack[y]=0; belong[y]=tot; W[tot]+=w[y]; V[tot]+=v[y]; }while(y!=x); }}int to[MAXN],pre[MAXN],nxt[MAXN],degree_in[MAXN];void ADD(int u,int v){ cnt++,to[cnt]=v,nxt[cnt]=pre[u],pre[u]=cnt;}int f[MAXN][MAXM];void dp(int x){ for(int i=0;i<=m;i++){ if(i
=W[x];j--){ for(int p=0;p<=j-W[x];p++){ f[x][j]=max(f[x][j],f[y][p]+f[x][j-p]); } } }}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]); if(d[i]!=0) add(d[i],i); } for(int i=1;i<=n;i++){ if(!dfn[i]) tarjan(i); } cnt=0; for(int i=1;i<=n;i++){ for(int j=first[i];j;j=head[j]){ int v=ver[j]; if(belong[i]!=belong[v]){ ADD(belong[i],belong[v]); degree_in[belong[v]]++; } } } for(int i=1;i<=tot;i++){ if(!degree_in[i]) ADD(tot+1,i); } dp(++tot); printf("%d\n",f[tot][m]); return 0;}

 

转载于:https://www.cnblogs.com/Juve/p/11172123.html

你可能感兴趣的文章
ubuntu触摸板双指滑动,页面滚动方向
查看>>
flex box布局
查看>>
php-fpm配置文件
查看>>
撩课-Web大前端每天5道面试题-Day16
查看>>
Python学习 Week1
查看>>
【bzoj3207】花神的嘲讽计划Ⅰ Hash+STL-map+莫队算法
查看>>
使用 polyfills 的简易方法
查看>>
Maven之(五)Maven仓库
查看>>
低耦合的理解与作用
查看>>
Python基础语法
查看>>
web前端性能优化汇总
查看>>
laravel5.4中ajax删除数据
查看>>
Crash的数字表格 BZOJ 2154 / jzptab BZOJ 2693
查看>>
分析百度降权的几个主要原因
查看>>
A*B 高静度
查看>>
jmeter(十五)Jmeter默认报告优化
查看>>
HTML5与HTML4的区别(2)
查看>>
ES DSL 基础查询语法学习笔记
查看>>
oracle中的exists 和not exists 用法详解
查看>>
4月10号总结
查看>>