您的位置:首页 > 其它

[HAOI2010] 软件安装

2017-01-21 11:30 363 查看

题目描述

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

5 5 6

2 3 4

0 1 1

样例输出

5

题目分析

根据题意,很容易想到金明的预算方案这道题,然后你就跪了,软件可以无限制地向上依赖,并不是主附件关系。

然后你就想到了树形背包,然后就得了40分(我就是这样的),因为软件可以互相依赖,A依赖B,B依赖A,要么全部选,要么全部不选,因此可以进行Tarjan缩点。

然后就陷入无限调试状态。

再见

源代码

#include<algorithm>
#include<iostream>
#include<iomanip>
#include<cstring>
#include<cstdlib>
#include<vector>
#include<cstdio>
#include<cmath>
#include<queue>
using namespace std;
inline const int Get_Int() {
int num=0,bj=1;
char x=getchar();
while(x<'0'||x>'9') {
if(x=='-')bj=-1;
x=getchar();
}
while(x>='0'&&x<='9') {
num=num*10+x-'0';
x=getchar();
}
return num*bj;
}
int Head[5005],TreeHead[5005],InDegree[5005],cnt=0,cnt2=0;
struct Edge {
int to,next;
} Edge[5005],Tree[5005];
struct Software {
int size,value;
} a[5005],New[5005];
void AddEdge(int from,int to) {
cnt++;
Edge[cnt].to=to;
Edge[cnt].next=Head[from];
Head[from]=cnt;
}
void AddNewEdge(int from,int to) {
cnt2++;
Tree[cnt2].to=to;
Tree[cnt2].next=TreeHead[from];
TreeHead[from]=cnt2;
}
int step=0,Dfn[5005],Lowlink[5005],Stack[5005],top=0,Instack[5005],Belong[5005],SCC=0;
void Tarjan(int Now) {
step++;
Lowlink[Now]=Dfn[Now]=step;
Stack[++top]=Now;
Instack[Now]=1;
for(int i=Head[Now]; i; i=Edge[i].next) {
int Next=Edge[i].to;
if(!Dfn[Next]) {
Tarjan(Next);
Lowlink[Now]=min(Lowlink[Now],Lowlink[Next]);
} else if(Instack[Next])Lowlink[Now]=min(Lowlink[Now],Dfn[Next]);
}
if(Lowlink[Now]==Dfn[Now]) {
SCC++;
int y;
do {
y=Stack[top--];
Belong[y]=SCC;
New[SCC].size+=a[y].size;
New[SCC].value+=a[y].value;
Instack[y]=0;
} while(y!=Now);
}
}
int n,Size,map[505][505],f[505][505];
void TreeDp(int Now) {
f[Now][New[Now].size]=New[Now].value;
for(int i=TreeHead[Now]; i; i=Tree[i].next) {
int Next=Tree[i].to;
TreeDp(Next);
for(int i=Size-New[Now].size; i>=0; i--)
for(int j=0; j<=i; j++)
f[Now][i+New[Now].size]=max(f[Now][i+New[Now].size],f[Now][i-j+New[Now].size]+f[Next][j]);
}
}
int main() {
n=Get_Int();
Size=Get_Int();
for(int i=1; i<=n; i++)a[i].size=Get_Int();
for(int i=1; i<=n; i++)a[i].value=Get_Int();
for(int i=1; i<=n; i++) {
int x=Get_Int();
if(x!=0)AddEdge(x,i);
}
for(int i=1; i<=n; i++)if(!Dfn[i])Tarjan(i);
for(int Now=1; Now<=n; Now++)
for(int i=Head[Now]; i; i=Edge[i].next) {
int Next=Edge[i].to;
if(!map[Belong[Now]][Belong[Next]]&&Belong[Now]!=Belong[Next]) {
map[Belong[Now]][Belong[Next]]=1;
InDegree[Belong[Next]]++;
AddNewEdge(Belong[Now],Belong[Next]);
}
}
for(int i=1; i<=SCC; i++)
if(InDegree[i]==0)AddNewEdge(SCC+1,i);
SCC++;
TreeDp(SCC);
printf("%d\n",f[SCC][Size]);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息