您的位置:首页 > 其它

洛谷 P2515 [HAOI2010]软件安装

2017-04-12 23:51 281 查看

题目描述

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

输出格式:

一个整数,代表最大价值

输入输出样例

输入样例#1:

3 105 5 62 3 40 1 1
输出样例#1:

5

哈哈,又是一道好题!
思路还是比较好想的,先tarjan缩点,重新建图,原图从基环树变成树,做树形dp,然而本人比较弱,树形dp没有一次写对。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<stack>
using namespace std;
const int N=105;
int n,m,cnt,dcnt,tim,d
,c
,w
,hd
,dfn
,low
,cc
,ww
,f
[505],belong
,du
;
bool ins
;
stack<int>stk;
struct edge
{
int to,nxt;
}v
;
void addedge(int x,int y)
{
v[++cnt].to=y;
v[cnt].nxt=hd[x];
hd[x]=cnt;
}
void tarjan(int u)
{
dfn[u]=low[u]=++tim;
ins[u]=1;
stk.push(u);
for(int i=hd[u];i;i=v[i].nxt)
{
if(!dfn[v[i].to])
{
tarjan(v[i].to);
low[u]=min(low[u],low[v[i].to]);
}
else if(ins[v[i].to])
low[u]=min(low[u],dfn[v[i].to]);
}
if(dfn[u]==low[u])
{
++dcnt;
while(1)
{
int t=stk.top();
stk.pop();
ins[t]=0;
belong[t]=dcnt;
if(u==t)
break;
}
}
}
void dp(int u,int fa)
{
for(int i=hd[u];i;i=v[i].nxt)
if(v[i].to!=fa)
{
dp(v[i].to,u);
for(int j=m-cc[u];j>=1;j--)
for(int k=1;k<=j;k++)
f[u][j]=max(f[u][j],f[u][j-k]+f[v[i].to][k]);
}
for(int i=m;i>=0;i--)
if(i>=cc[u])
f[u][i]=f[u][i-cc[u]]+ww[u];
else
f[u][i]=0;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&c[i]);
for(int i=1;i<=n;i++)
scanf("%d",&w[i]);
for(int i=1;i<=n;i++)
{
scanf("%d",&d[i]);
if(d[i])
addedge(d[i],i);
}
//缩点
for(int i=1;i<=n;i++)
if(!dfn[i])
tarjan(i);
//重新建图
for(int i=1;i<=n;i++)
cc[belong[i]]+=c[i],ww[belong[i]]+=w[i];
memset(hd,0,sizeof(hd));
cnt=0;
for(int i=1;i<=n;i++)
if(d[i]&&belong[d[i]]!=belong[i])
{
addedge(belong[d[i]],belong[i]);
du[belong[i]]++;
}
for(int i=1;i<=dcnt;i++)
if(!du[i])
addedge(0,i);
//树形dp
dp(0,-1);
printf("%d\n",f[0][m]);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  动态规划 图论