#树形dp#洛谷 4395 [BOI2003]Gem 气垫车

题目

给出一棵树,要求你为树上的结点标上权值,权值可以是任意的正整数

唯一的限制条件是相邻的两个结点不能标上相同的权值,要求一种方案,使得整棵树的总价值最小。


分析

每个结点的权值最大可能为 logn

所以直接设 dp[x][y] 表示点 x 选择的权值为 y 时的最小总价值,

维护最大值和次大值就可以做到 O(nlogn)


代码

#include <iostream>
#include <vector>
using namespace std;
const int N=10011; vector<int>G[N];
int dp[N][21],n,fi[N],se[N],ans=0x3f3f3f3f;
void dfs(int x,int fa){
	int len=G[x].size();
	dp[x][0]=0x3f3f3f3f;
	for (int i=1;i<=20;++i) dp[x][i]=i;
	for (int i=0;i<len;++i){
		int y=G[x][i];
		if (y==fa) continue;
		dfs(y,x);
		for (int j=1;j<=20;++j)
		if (fi[y]==j) dp[x][j]+=dp[y][se[y]];
		    else dp[x][j]+=dp[y][fi[y]];
	}
	for (int i=1;i<=20;++i)
	if (dp[x][fi[x]]>dp[x][i]) se[x]=fi[x],fi[x]=i;
	    else if (dp[x][se[x]]>dp[x][i]) se[x]=i; 
}
int main(){
	ios::sync_with_stdio(0);
	cin>>n;
	for (int i=1;i<n;++i){
		int x,y; cin>>x>>y;
		G[x].push_back(y);
		G[y].push_back(x);
	}
	dfs(1,0);
	for (int i=1;i<=20;++i)
	    if (ans>dp[1][i]) ans=dp[1][i];
	return !printf("%d",ans);
}
posted @   lemondinosaur  阅读(28)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示