基环树上dp--luoguP1453 城市环路

本文深入探讨了在基环树结构上进行动态规划的方法。首先介绍了如何在树上进行DP,接着详细阐述了如何处理环上的DP,特别关注了环上节点选择的约束条件。通过具体代码实例,展示了算法实现的细节,包括环的检测、状态转移方程及最终结果的计算。

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

传送门

quq基环树上的dp

先dp树再dp环,然后注意环上还要记录一维开始那个节点有没有选,因为最后一个节点和第一个也不能冲突

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#define N 100005
using namespace std;
int n,val[N],cnt,head[N],stk[N],top,s,t;
double k,f[N][2],g[N][2][2];
bool flg,vis[N],isc[N];
vector<int> cir;

inline int rd(){
	int x=0,f=1;char c=' ';
	while(c<'0' || c>'9') f=c=='-'?-1:1,c=getchar();
	while(c<='9' && c>='0') x=x*10+c-'0',c=getchar();
	return x*f;
}

struct EDGE{
	int to,nxt;
}edge[N<<1];

inline void add(int x,int y){
	edge[++cnt].to=y; edge[cnt].nxt=head[x]; head[x]=cnt;
}
inline double max(double x,double y){return x>=y?x:y;}

inline void dfs(int u,int fa){
	if(vis[u]){
		while(stk[top]!=u){
			cir.push_back(stk[top]);
			isc[stk[top--]]=1;
		}
		cir.push_back(u); isc[u]=1; flg=1;
		return;
	}
	vis[u]=1; stk[++top]=u;
	for(int i=head[u];i;i=edge[i].nxt){
		int v=edge[i].to; if(v==fa) continue;
		dfs(v,u); if(flg) return;
		top--; vis[v]=0;
	}
	return;
}

inline void DP(int u,int fa){
	f[u][1]=1.0*val[u]*k;
	for(int i=head[u];i;i=edge[i].nxt){
		int v=edge[i].to; if(v==fa || isc[v])continue;
		DP(v,u);
		f[u][1]+=f[v][0]; f[u][0]+=max(f[v][0],f[v][1]);
	} return;
}

int main(){
	n=rd();
	for(int i=1;i<=n;i++) val[i]=rd();
	for(int i=1;i<=n;i++){
		int x=rd(),y=rd(); x++,y++;
		add(x,y); add(y,x);
	}
	scanf("%lf",&k);
	dfs(1,0); memset(vis,0,sizeof vis);
	for(int i=0;i<cir.size();i++) DP(cir[i],0);
	s=cir[0],t=cir[cir.size()-1];
	g[s][0][0]=f[s][0],g[s][1][1]=f[s][1];
	for(int i=1;i<cir.size();i++){
		int now=cir[i],pre=cir[i-1];
		if(now==t){
			g[now][0][0]=max(g[pre][1][0],g[pre][0][0])+f[now][0];
			g[now][0][1]=max(g[pre][1][1],g[pre][0][1])+f[now][0];
			g[now][1][0]=g[pre][0][0]+f[now][1];
		}
		else{
			g[now][0][0]=max(g[pre][1][0],g[pre][0][0])+f[now][0];
			g[now][0][1]=max(g[pre][1][1],g[pre][0][1])+f[now][0];
			g[now][1][0]=g[pre][0][0]+f[now][1];
			g[now][1][1]=g[pre][0][1]+f[now][1];
		}
	}
	printf("%.1lf",max(g[t][0][0],max(g[t][1][0],g[t][0][1])));
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值