2427: [HAOI2010]软件安装

连接:点击打开链接

因为可能有环,即要么一起选,要么都不选,做一期强联通缩点,在树上dp即可。

注意,每个点做完要延父亲边更新一次。

code:

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
using namespace std;
int w[210],v[210],d[210],f[510][210],g[210],n,m;
int dfn[110],low[110],id,top,sta[110],belong[110],cnt=0;
bool u[110];
struct node{
	int y,next;
}a[210];int last[210],len=0;
void ins(int x,int y)
{
	a[++len].y=y;
	a[len].next=last[x];last[x]=len;
}
void dp(int x)
{
	g[x]=g[d[x]]+w[x];
	for(int i=m;i>=g[x];i--)
		f[i][x]=max(f[i][x],f[i-w[x]][d[x]]+v[x]);
	for(int i=last[x];i;i=a[i].next) dp(a[i].y);
	int fa=d[x];
	while(1)
	{
		for(int i=0;i<=m;i++) f[i][fa]=max(f[i][fa],f[i][x]);
		if(fa==0) break;
		fa=d[fa];
	}
}
void dfs(int x)
{
	dfn[x]=low[x]=++id;
	sta[++top]=x;u[x]=true;
	if(d[x]!=0)
	{
		int y=d[x];
		if(dfn[y]==-1)
		{
			dfs(y);
			low[x]=min(low[x],low[y]);
		}
		else
			if(u[y]) low[x]=min(low[x],dfn[y]);
	}
	if(low[x]==dfn[x])
    {
        cnt++;int i;
        do
		{
        	i=sta[top--];
			w[cnt]+=w[i];v[cnt]+=v[i];
        	u[i]=false;
        	belong[i]=cnt;
        }while(i!=x);
    }
}
int main()
{
	scanf("%d %d",&n,&m);cnt=n;
	for(int i=1;i<=n;i++) scanf("%d",&w[i]);
	for(int i=1;i<=n;i++) scanf("%d",&v[i]);
	for(int i=1;i<=n;i++) scanf("%d",&d[i]);
	memset(dfn,-1,sizeof(dfn));
	memset(u,false,sizeof(u));id=top=0;
	for(int i=1;i<=n;i++)
		if(dfn[i]==-1) dfs(i);
	for(int i=1;i<=n;i++)
	{
		if(belong[i]!=belong[d[i]])
			d[belong[i]]=belong[d[i]],ins(belong[d[i]],belong[i]);
	}
	for(int i=n+1;i<=cnt;i++) if(d[i]==0) dp(i);
	printf("%d",f[m][0]);
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值