题目描述

现在我们的手头有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 )

输出格式:

一个整数,代表最大价值

思路:

望过去满眼的树形DP

和前面写的选课一模一样,只是cost需要输入

但很显然,你会这样

为什么呢?

后来想了半天,才发现

如果1依赖于2,2依赖于2,3依赖于1的化,这几个个点其实也能选,不过要选得一起选

所以,我们要用tarjan来缩点

把所有满足上图关系的点变为一个新点,并且与0连边即可

Q:环套树怎么办?

因为一个点只唯一依赖另一个点,所以入边一定为1

所以一定是环到树,不可能树到环,所以缩点没问题

懒了一下,用了stl

代码:

// luogu-judger-enable-o2
#include<iostream>
#include<stack>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#define rii register int i
#define rij register int j
#define rik register int k
using namespace std;
const int N=;const int M=;
struct E{
int to,nxt;
}ed[N<<];
int H[N<<],cnt;
stack<int>sta;
bool ins[N];
int dp[N][M],v[N],w[N],d[N];
int tot,dfn[N],low[N];
int num,col[N],fv[N],fw[N];
int n,m,rd[N];
void add(int x,int y)
{
cnt++;
ed[cnt].to=y;
ed[cnt].nxt=H[x];
H[x]=cnt;
return;
}
void read(int &in)
{
int x=,f=;
char ch;
for(ch=getchar();(ch<''||ch>'')&&ch!='-';ch=getchar());
if(ch=='-')
{
f=-;
ch=getchar();
}
while(ch>=''&&ch<='')
{
x=(x<<)+(x<<)+ch-'';
ch=getchar();
}
in=x*f;
return;
}
void tarjan(int x)
{
dfn[x]=low[x]=++tot;
ins[x]=true;sta.push(x);
int t,k;
for(rii=H[x];i;i=ed[i].nxt)
{
t=ed[i].to;
if(!dfn[t])
{
tarjan(t);
low[x]=min(low[x],low[t]);
}
else if(ins[t])
{
low[x]=min(low[x],dfn[t]);
}
}
if(low[x]==dfn[x])
{
num++;
do
{
k=sta.top();
sta.pop();
col[k]=num;
fw[num]+=w[k];
fv[num]+=v[k];
ins[k]=false;
}
while(k!=x);
}
return;
}
void dfs(int x)
{
for(rii=fw[x];i<=m;i++)
{
dp[x][i]=fv[x];
}
int t;
for(rii=H[x];i;i=ed[i].nxt)
{
t=ed[i].to;
dfs(t);
for(rij=m-fw[x];j>=;j--)
{
for(rik=;k<=j;k++)
{
dp[x][j+fw[x]]=max(dp[x][j+fw[x]],dp[x][j+fw[x]-k]+dp[t][k]);
}
}
}
return;
}
int main()
{
// freopen("software.in","r",stdin);
// freopen("software.out","w",stdout);
read(n);
read(m);
for(rii=;i<=n;i++)
{
read(w[i]);
}
for(rii=;i<=n;i++)
{
read(v[i]);
}
for(rii=;i<=n;i++)
{
read(d[i]);
if(d[i])
{
add(d[i],i);
}
}
for(rii=;i<=n;i++)
{
if(!dfn[i])
{
tarjan(i);
}
}
memset(H,,sizeof(H));
cnt=;
for(rii=;i<=n;i++)
{
if(col[i]!=col[d[i]]&&d[i])
{
add(col[d[i]],col[i]);
rd[col[i]]++;
}
}
for(rii=;i<=num;i++)
{
if(!rd[i])
{
add(num+,i);
}
dfs(num+);
}
printf("%d\n",dp[num+][m]);
return ;
}
 // luogu-judger-enable-o2
#include<iostream>
#include<stack>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#define rii register int i
#define rij register int j
#define rik register int k
using namespace std;
const int N=;const int M=;
struct E{
int to,nxt;
}ed[N<<];
int H[N<<],cnt;
stack<int>sta;
bool ins[N];
int dp[N][M],v[N],w[N],d[N];
int tot,dfn[N],low[N];
int num,col[N],fv[N],fw[N];
int n,m,rd[N];
void add(int x,int y)
{
cnt++;
ed[cnt].to=y;
ed[cnt].nxt=H[x];
H[x]=cnt;
return;
}
void read(int &in)
{
int x=,f=;
char ch;
for(ch=getchar();(ch<''||ch>'')&&ch!='-';ch=getchar());
if(ch=='-')
{
f=-;
ch=getchar();
}
while(ch>=''&&ch<='')
{
x=(x<<)+(x<<)+ch-'';
ch=getchar();
}
in=x*f;
return;
}
void tarjan(int x)
{
dfn[x]=low[x]=++tot;
ins[x]=true;sta.push(x);
int t,k;
for(rii=H[x];i;i=ed[i].nxt)
{
t=ed[i].to;
if(!dfn[t])
{
tarjan(t);
low[x]=min(low[x],low[t]);
}
else if(ins[t])
{
low[x]=min(low[x],dfn[t]);
}
}
if(low[x]==dfn[x])
{
num++;
do
{
k=sta.top();
sta.pop();
col[k]=num;
fw[num]+=w[k];
fv[num]+=v[k];
ins[k]=false;
}
while(k!=x);
}
return;
}
void dfs(int x)
{
for(rii=fw[x];i<=m;i++)
{
dp[x][i]=fv[x];
}
int t;
for(rii=H[x];i;i=ed[i].nxt)
{
t=ed[i].to;
dfs(t);
for(rij=m-fw[x];j>=;j--)
{
for(rik=;k<=j;k++)
{
dp[x][j+fw[x]]=max(dp[x][j+fw[x]],dp[x][j+fw[x]-k]+dp[t][k]);
}
}
}
return;
}
int main()
{
// freopen("software.in","r",stdin);
// freopen("software.out","w",stdout);
read(n);
read(m);
for(rii=;i<=n;i++)
{
read(w[i]);
}
for(rii=;i<=n;i++)
{
read(v[i]);
}
for(rii=;i<=n;i++)
{
read(d[i]);
if(d[i])
{
add(d[i],i);
}
}
for(rii=;i<=n;i++)
{
if(!dfn[i])
{
tarjan(i);
}
}
memset(H,,sizeof(H));
cnt=;
for(rii=;i<=n;i++)
{
if(col[i]!=col[d[i]]&&d[i])
{
add(col[d[i]],col[i]);
rd[col[i]]++;
}
}
for(rii=;i<=num;i++)
{
if(!rd[i])
{
add(num+,i);
}
dfs(num+);
}
printf("%d\n",dp[num+][m]);
return ;

[HAOI2010]软件安装(树形背包,tarjan缩点)的更多相关文章

  1. BZOJ2427:[HAOI2010]软件安装(树形DP,强连通分量)

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

  2. HAOI2010软件安装(树形背包)

    HAOI2010软件安装(树形背包) 题意 有n个物品,每个物品最多会依赖一个物品,但一个物品可以依赖于一个不独立(依赖于其它物品)的物品,且可能有多个物品依赖一个物品,并且依赖关系可能形成一个环.现 ...

  3. 【BZOJ2427】[HAOI2010]软件安装 Tarjan+树形背包

    [BZOJ2427][HAOI2010]软件安装 Description 现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi.我们希望从中选择一些软件安装到一台磁盘容量为 ...

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

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

  5. Tarjan+树形DP【洛谷P2515】[HAOI2010]软件安装

    [洛谷P2515][HAOI2010]软件安装 题目描述 现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi.我们希望从中选择一些软件安装到一台磁盘容量为M计算机上,使得 ...

  6. [HAOI2010]软件安装(Tarjan,树形dp)

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

  7. BZOJ_2427_[HAOI2010]软件安装_tarjan+树形DP

    BZOJ_2427_[HAOI2010]软件安装_tarjan+树形DP 题意: 现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi.我们希望从中选择一些软件安装到一台磁 ...

  8. [BZOJ2427][HAOI2010]软件安装(Tarjan+DP)

    2427: [HAOI2010]软件安装 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1987  Solved: 791[Submit][Statu ...

  9. bzoj2427:[HAOI2010]软件安装(Tarjan+tree_dp)

    2427: [HAOI2010]软件安装 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1053  Solved: 424[Submit][Statu ...

  10. 【BZOJ2427】[HAOI2010]软件安装(动态规划,Tarjan)

    [BZOJ2427][HAOI2010]软件安装(动态规划,Tarjan) 题面 BZOJ 洛谷 题解 看到这类题目就应该要意识到依赖关系显然是可以成环的. 注意到这样一个性质,依赖关系最多只有一个, ...

随机推荐

  1. HTML代码中<%%>、<%=%>、<%:%>

    <%%>之间可以写服务器端代码 比如 <% for(var i=0;i<10;i++){%> <%=%>获取后台的变量值,比如后台一个session[&quo ...

  2. 2、Spring之AOP

    AOP术语 通知:定义了切面是什么以及何时使用.除了要描述页面要完成的工作,通知还解决了何时执行这个工作的问题. 连接点:连接点是一个物理的存在.这个点可以是调用方法时.抛出异常时.甚至是修改一个字段 ...

  3. stark——查看页面编辑删除按钮

    一.数据列表 设计查页面,主要展示两部分内容,表头部分和数据部分, 表头通过遍历list_display和默认要显示的编辑和删除字段. 1.数据构建 (1)service/stark.py,后台数据构 ...

  4. 随学笔记 partAdded

    随学笔记: RectangularDropShadow为矩形对象添加阴影,DropShadowFilter可以为任意形状对象添加阴影. BorderContainer和Panel等容器使用的就是Rec ...

  5. Android 使用RecyclerView优雅实现悬浮标题通讯录

    项目地址:https://github.com/hgDendi/ContactsList 界面概览: ContactsListDemo ContactsListDemo2 概要 如图,主要简单划分为两 ...

  6. wxpython 对话框

    . 消息对话框(wx.MessageDialog) 消息对话框 与用户通信最基本的机制是wx.MessageDialog,它是一个简单的提示框. wx.MessageDialog可用作一个简单的OK框 ...

  7. PrintDocument打印、预览、打印机设置和打印属性的方法(较完整) .

    private void Form1_Load(object sender, System.EventArgs e) { //获取或设置一个值,该值指示是否发送到文件或端口 printDocument ...

  8. 【Spring实战】—— 14 传统的JDBC实现的DAO插入和读取

    从这篇开始学习Spring的JDBC,为了了解Spring对于JDBC的作用,先通过JDBC传统的流程,实现一个数据库的插入和读取. 从这篇你可以了解到: 1 传统的JDBC插入和读取的过程. 2 如 ...

  9. 通过vue-cli3构建一个SSR应用程序

    1.前沿 1.1.什么是SSR SSR(服务端渲染)顾名思义就是将页面在服务端渲染完成后在客户端直接展示. 1.2.客户端渲染与服务端渲染的区别 传统的SPA模式 即客户端渲染的模式 Vue.js构建 ...

  10. 修改CPAN安装源

    更新CPAN镜像源的方法,以CentOS 6.5为例. 存储CPAN设置信息的文件路径为: /usr/share/perl/CPAN/Config.pm 使用vi打开文件 vi /usr/share/ ...