您的位置:首页 > 其它

luogu P2515 [HAOI2010]软件安装

2017-12-09 07:48 453 查看

题目描述

现在我们的手头有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 10
5 5 6
2 3 4
0 1 1


输出样例#1: 复制
5

缩点后树形dp


#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 1007;

inline int read() {
int x=0,f=1;
char c=getchar() ;
while(c<'0'||c>'9'){ if(c=='-')f=-1;c=getchar();};
while(c<='9'&&c>='0')x=x*10+c-'0',c=getchar();
return x*f;
}
int w[maxn],v[maxn],n,m;
struct node {
int v,next;
}edge[maxn*5],E[maxn*10];
int num=0,N=0,H[maxn*2],head[maxn];
inline void add_edge(int u,int v) {
edge[++num].v=v;edge[num].next=head[u];head[u]=num;
}
inline void ADD(int u,int v) {
E[++N].v=v;E
.next=H[u];H[u]=N;
}
int dfn[maxn],low[maxn],color[maxn],color_cnt=0,stack[maxn],vul[maxn],wul[maxn];
bool vis[maxn];int top;
void tarjan(int x) {
dfn[x]=low[x]=++num;
vis[x]=1;stack[++top]=x;
for(int i=head[x];i;i=edge[i].next) {
int v=edge[i].v;
if(!dfn[v]) {
tarjan(v);
low[x]=std::min(low[x],low[v]);
}
else if(vis[v]) low[x]=min(low[x],dfn[v]);
}
if(low[x]==dfn[x]) {
color_cnt++;
while(stack[top+1]!=x) {
vis[stack[top]]=0;
color[stack[top]]=color_cnt;
vul[color_cnt]+=v[stack[top]];
wul[color_cnt]+=w[stack[top]];top--;
}
}
}
int dp[maxn*2][maxn*5];
void dfs(int x) {
for(int i=wul[x];i<=m;++i) dp[x][i]=vul[x];
for(int i=H[x];i;i=E[i].next) {
int vv=E[i].v;
dfs(vv);
for(int j=m-wul[x];j>=0;j--)
for(int k=0;k<=j;k++) {
dp[x][j+wul[x]]=max(dp[x][j+wul[x]],dp[x][j+wul[x]-k]+dp[vv][k]);
}
}
//for(int i=m;i>=0;i--)
//if(w[i]<=i)dp[x][i]=v[x];
//else dp[x][i]=0;
}
bool rd[maxn*2];
int main() {
n=read(),m=read();
for(int i=1;i<=n;++i) w[i]=read();
for(int i=1;i<=n;++i) v[i]=read();
for(int a,i=1;i<=n;++i) {
a=read();
if(a) add_edge(a,i);
}num=0;
//for(int i=1;i<=n;++i) {
//    color[i]=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;j=edge[j].next) {
int vv=edge[j].v;
if(color[i]!=color[vv]) {
ADD(color[i],color[vv]);
rd[color[vv]]=1;
}
}
for(int i=1;i<=n;++i) {
if(!rd[color[i]])ADD(0,color[i]);
}
dfs(0);
printf("%d\n",dp[0][m]);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: