【SSL】2400&【洛谷】P2515软件安装

【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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值