P2515 [HAOI2010] 软件安装

      ~~~~~      P2515 [HAOI2010] 软件安装       ~~~~~      总题单链接

思路

      ~~~~~      发现构成的图是一个森林和一些环。

      ~~~~~      对于森林,建一个虚点然后树形 D P DP DP 即可。

      ~~~~~      对于环,发现要么把这个环上的每一个点都选了,要么每一个都不选。所以可以先缩点

      ~~~~~      缩点后跑树形 d p dp dp 就行了。

代码

#include<bits/stdc++.h>
#define ll long long
#define fir first
#define sec second
using namespace std;

ll n,m,v[505],w[505];
ll dfn[505],low[505],tot;
ll scc[505],din[505],cnt;
ll stk[505],ins[505],top;
vector<ll>eg[505],ng[505];
ll scw[505],scv[505],dp[505][505];

void Tarjan(ll p){
	dfn[p]=low[p]=++tot;
	stk[++top]=p;ins[p]=1;
	for(ll v:eg[p]){
		if(!dfn[v]){
			Tarjan(v);
			low[p]=min(low[p],low[v]);
		}
		else if(ins[v])low[p]=min(low[p],dfn[v]);
	}
	if(low[p]==dfn[p]){
		cnt++;
		while(1){
			ll z=stk[top--];
			ins[z]=0;
			scc[z]=cnt;
			scv[cnt]+=v[z];
			scw[cnt]+=w[z];
			if(z==p)break;
		}
	}
}

void dfs_dp(ll p){
	if(scv[p]<=m)dp[p][scv[p]]=scw[p];
	for(ll v:ng[p]){
		dfs_dp(v);
		for(ll i=m;i>=scv[p];i--)
			for(ll j=m;j>=0;j--)
				if(i+j<=m)
					dp[p][i+j]=max(dp[p][i+j],dp[p][i]+dp[v][j]);
	}
}

signed main(){
	ios::sync_with_stdio(false);
	
	cin>>n>>m;
	for(ll i=1;i<=n;i++)cin>>v[i];
	for(ll i=1;i<=n;i++)cin>>w[i];
	for(ll i=1;i<=n;i++){
		ll f;cin>>f;
		eg[f].push_back(i);
	}
	
	for(ll i=1;i<=n;i++)
		if(!dfn[i])Tarjan(i);
		
	for(ll u=1;u<=n;u++)
		for(ll v:eg[u]){
			if(scc[u]==scc[v])continue;
			ng[scc[u]].push_back(scc[v]);
			din[scc[v]]++;
		}
	for(ll i=1;i<=cnt;i++)
		if(!din[i])ng[0].push_back(i);
			
	memset(dp,-0x3f,sizeof(dp));
	dfs_dp(0);
	
	ll ans=0;
	for(ll i=0;i<=m;i++)
		ans=max(ans,dp[scc[0]][i]);
	cout<<ans;
	
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值