#基环树,树形dp#洛谷 2607 JZOJ 1723 骑士

本文探讨了一种解决有环图中特定问题的方法,通过将环转化为树,使用树形动态规划(DP)求解最大值问题。首先连接环形成树结构进行首次树形DP,然后断开环再次运行树形DP,最终结果为两次DP的最大值之和。

题目

有环的没有上司的舞会


分析

那么有环那就不是树形dp了,如何处理环,可以先连起来,树形dp,再把环断掉,再跑一次树形dp,两次的最大值即为答案


代码

#include <cstdio>
#include <cctype>
#define rr register
using namespace std;
const int N=1000010; long long dp[N][2],ans;
struct node{int y,next;}e[N];
int bk[N],ls[N],n,a[N],root,k=1; bool v[N];
inline long long max(long long a,long long b){return (a>b)?a:b;}
inline signed iut(){
	rr int ans=0; rr char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans;
}
inline void add(int x,int y){e[++k]=(node){y,ls[x]}; ls[x]=k;}
inline void dfs(int x){
	v[x]=1; dp[x][0]=0; dp[x][1]=a[x];
	for (rr int i=ls[x];i;i=e[i].next)
	if (e[i].y!=root){
		dfs(e[i].y);
		dp[x][0]+=max(dp[e[i].y][0],dp[e[i].y][1]);//该点不选可以获得子节点
		dp[x][1]+=dp[e[i].y][0];//该点选了子节点选不了
	}else dp[e[i].y][1]=-707406378;
}
inline void circ(int x){
	v[root=x]=1;
	while (!v[bk[root]]) v[root=bk[root]]=1;//找环
	dfs(root);//先跑一次
	rr long long t=max(dp[root][0],dp[root][1]);
	v[root]=1; dfs(root=bk[root]);//再跑一次
	ans+=max(t,max(dp[root][0],dp[root][1]));
}
signed main(){
	n=iut();
	for (rr int i=1;i<=n;++i) a[i]=iut(),add(bk[i]=iut(),i);
	for (rr int i=1;i<=n;++i) if (!v[i]) circ(i);//避免重复
	return !printf("%lld",ans);
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值