【DP】【树形DP】Splot

这是一篇关于树形动态规划(DP)的博客,分析了一道极具挑战性的题目。作者指出,可以将串联和并联操作视为新增节点,并将其连接的两个点作为新节点的子节点。通过记录四种状态,可以实现树形DP的转移。文章重点讨论了不同情况下的状态转移策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:

在这里插入图片描述
在这里插入图片描述


分析:

很有毒的树形DP题

每个串联和并联都可以看作:新加一个点,将串(并)联的两个点作为新点的儿子。

然后,可以记录4种状态进行树形DP
在这里插入图片描述
转移分串并联讨论一下就可以了。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#define SF scanf
#define PF printf
#define MAXN 1000010
#define INF 0x3FFFFFFF
using namespace std;
char s[MAXN];
int tot;
struct node{
	int typ;
	node *ch[2];
	int dp[5];
	int f1,f2,siz;	
}Pool[MAXN];
node *ncnt=Pool,*rt=Pool;
char* build_tree(node *&x,char *s){
	x=++ncnt;
	if(*s=='P'){
		s++;
		x->typ=1;
		x->f1=('o'!=*s++);
		s++;
		s=build_tree(x->ch[0],s);
		s=build_tree(x->ch[1],s);
		s++;
		x->f2=('o'!=*s++); 
		s++;
		x->siz=x->f1+x->f2;
	}
	else if(*s=='S'){
		s++;
		x->typ=2;
		s=build_tree(x->ch[0],s);
		s=build_tree(x->ch[1],s);
		s++;
	}
	else if(*s=='o'){
		s++;
		x->typ=3;
	}
	else if(*s=='x'){
		s++;
		x->typ=4;
		x->siz=1;
	}
	return s;
}
int gmax(int &x,int y){
	x=max(x,y);
}	
void dfs(node *x){
	x->dp[1]=x->dp[2]=x->dp[3]=x->dp[4]=-INF;
	if(x->typ==4){
		x->dp[1]=x->dp[2]=x->dp[3]=1;
		return ;
	}
	if(x->typ==3){
		x->dp[1]=x->dp[2]=x->dp[3]=1;
		x->dp[4]=0;
		return ;
	}
	dfs(x->ch[0]);
	dfs(x->ch[1]);
	x->siz=x->siz+x->ch[0]->siz+x->ch[1]->siz;
	node *l=x->ch[0];
	node *r=x->ch[1];
	if(x->typ==2){
		if(r->siz==0) gmax(x->dp[1],l->dp[1]);
		if(l->siz==0) gmax(x->dp[2],r->dp[2]);
		gmax(x->dp[1],l->dp[4]+r->dp[1]);
		gmax(x->dp[2],l->dp[2]+r->dp[4]);
		gmax(x->dp[3],l->dp[1]+r->dp[2]);
		gmax(x->dp[3],l->dp[3]+r->dp[4]);
		gmax(x->dp[3],l->dp[4]+r->dp[3]);
		gmax(x->dp[4],l->dp[4]+r->dp[4]);
	}
	else if(x->typ==1){
		for(int mask=0;mask<4;mask++){
			int s=mask&1;
			int t=mask&2;
			if(s==0&&x->f1) continue;
			if(t==0&&x->f2) continue;
			if(s&&t){
				if(l->siz==0&&r->siz==0)
					gmax(x->dp[3],2);
			}
			else if(s){
				if(l->siz==0&&r->siz==0)
					gmax(x->dp[1],1);
				gmax(x->dp[2],l->dp[4]+r->dp[2]+1);
				gmax(x->dp[2],l->dp[2]+r->dp[4]+1);
				gmax(x->dp[3],l->dp[2]+r->dp[2]+1);
			}
			else if(t){
				if(l->siz==0&&r->siz==0)
					gmax(x->dp[2],1);
				gmax(x->dp[1],l->dp[4]+r->dp[1]+1);
				gmax(x->dp[1],l->dp[1]+r->dp[4]+1);
				gmax(x->dp[3],l->dp[1]+r->dp[1]+1);
			}
			else{
				gmax(x->dp[1],l->dp[1]+r->dp[1]);
				gmax(x->dp[1],l->dp[4]+r->dp[3]);
				gmax(x->dp[1],l->dp[3]+r->dp[4]);
				
				gmax(x->dp[2],l->dp[2]+r->dp[2]);
				gmax(x->dp[2],l->dp[3]+r->dp[4]);
				gmax(x->dp[2],l->dp[4]+r->dp[3]);
				
				gmax(x->dp[3],l->dp[3]+r->dp[3]);
				
				gmax(x->dp[4],l->dp[4]+r->dp[3]);
				gmax(x->dp[4],l->dp[3]+r->dp[4]);
			}
		}
	}
}
int main(){
	freopen("splot.in","r",stdin);
	freopen("splot.out","w",stdout);
	SF("%s",s);	
	build_tree(rt,s);
	dfs(rt);
	PF("%d",rt->dp[1]);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值