【SSL】2400&【洛谷】P2515软件安装
Time Limit:10000MS
Memory Limit:65536K
Case Time Limit:1000MS
Description
现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi。我们希望从中选择一些软件安装到一台磁盘容量为M计算机上,使得这些软件的价值尽可能大(即Vi的和最大)。
但是现在有个问题:软件之间存在依赖关系,即软件i只有在安装了软件j(包括软件j的直接或间接依赖)的情况下才能正确工作(软件i依赖软件j)。幸运的是,一个软件最多依赖另外一个软件。如果一个软件不能正常工作,那么它能够发挥的作用为0。
我们现在知道了软件之间的依赖关系:软件i依赖软件Di。现在请你设计出一种方案,安装价值尽量大的软件。一个软件只能被安装一次,如果一个软件没有依赖则Di=0,这时只要这个软件安装了,它就能正常工作。
Input
第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)
Output
第1行:一个整数,代表最大价值。
Sample Input
3 10
5 5 6
2 3 4
0 1 1
Sample Output
5
Hint
思路
在选课的基础上
判环,缩点
用拓扑排序判环
多叉树转二叉树
代码
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
struct jgt
{
int x,nxt;
}e[1000010];
int n,m,sd[1010],l[1010],r[1010],head[1010],f[1010][1010],ins[1010],w[1010],v[1010],fa[1010],wt[1010],vt[1010];//l:child,r:brother
bool vis[1010];
void DFS(int x)
{
int i;
for(vis[x]=1,i=head[x];i;i=e[i].nxt)
if(!vis[e[i].x])
{
ins[e[i].x]--;
if(!ins[e[i].x])DFS(e[i].x);
}
return;
}
void input()
{
int i,tot,tem;
memset(l,0,sizeof(l));
memset(r,0,sizeof(r));
memset(ins,0,sizeof(ins));
memset(head,0,sizeof(head));
memset(f,-1,sizeof(f));
scanf("%d%d",&n,&m);
for(i=0;i<=2*n;i++)sd[i]=i;
for(i=1;i<=n;i++)scanf("%d",&wt[i]);
for(i=1;i<=n;i++)scanf("%d",&vt[i]);
for(i=1;i<=n;i++)scanf("%d",&fa[i]),ins[fa[i]]++,e[i].nxt=head[i],e[i].x=fa[i],head[i]=i;
for(i=1;i<=n;i++)if(!vis[i]&&!ins[i])DFS(i);
for(i=1,tot=n;i<=n;i++)
if(!vis[i])
{
for(tot++,tem=i;!vis[tem];tem=fa[tem])sd[tem]=tot,w[tot]+=wt[tem],v[tot]+=vt[tem],vis[tem]=1;
r[tot]=l[0],l[0]=tot;
}
for(i=1;i<=n;i++)
if(sd[i]==i)r[sd[i]]=l[sd[fa[i]]],l[sd[fa[i]]]=sd[i],w[sd[i]]=wt[i],v[sd[i]]=vt[i];
return;
}
int TREEDP(int x,int y)//树状DP
{
int i;
if(f[x][y]>-1)return f[x][y];
if(x==0||y==0)return f[x][y]=0;
for(f[x][y]=TREEDP(r[x],y),i=0;i<=y-w[x];i++)f[x][y]=max(f[x][y],TREEDP(r[x],i)+TREEDP(l[x],y-i-w[x])+v[x]);
return f[x][y];
}
int main()
{
input(),printf("%d",TREEDP(l[0],m));
return 0;
}