「CF375E」Red and Black Tree「树形DP」

题意

给定一个结点颜色红或黑的树,问最少进行多少次交换黑、红结点使得每个红结点离最近的黑结点距离xx

1n500,1x1091n500,1x109

题解

不是红黑树

据说可有单纯形做,这里讲的还是树形dp的做法

考虑交换比较费劲,直接在nn个结点里选mm个(mm是黑结点个数),如果原来是红结点产生11的代价

dp[u][k][a]dp[u][k][a]表示uu子树内选了kk个黑点,uu选择的黑结点是aa(这里为了方便,不定义为最近的黑结点)的最小代价(若aa在子树外,不考虑aa的代价)。这个状态相当于树形背包加一维。

考虑转移:新加入了子树vv。原信息dp[u][su][a]dp[u][su][a],子树信息dp[v][su][b]dp[v][su][b]

  1. a=ba=b:加起来转移到dp[u][su+sv][a]dp[u][su+sv][a]上。
  2. bbvv子树中:此时a一定不在vv子树中。如果在子树中只要考虑a=ba=b,上面考虑过了。加起来转移到dp[u][su+sv][a]dp[u][su+sv][a]。(实现时直接对于每个子树外的aa加上最小dp值就好)
  3. bbvv子树外:这时候abab一定是不优的。aavv子树内,把b改aa不会更差;a也不在vv子树中,让a=ba=bb=ab=a一定有一种不会更差。所以不转移。

注意使用short类型防止MLE。

#include <algorithm>
#include <cstdio>
using namespace std;
const int N = 505;
struct Edge {
	short v, nxt; int w;
} e[N * 2];
short hd[N], sz[N], pos[N], w[N], n, m, ec;
short dl[N], dr[N], idx, dp[N][N][N], t[N][N];
int x, dis[N][N];
void clr() {
	fill(hd + 1, hd + n + 1, -1); ec = 0;
}
void add(short u, short v, int w) {
	e[ec] = (Edge) {v, hd[u], w}; hd[u] = ec ++;
}
void dfs0(int *d, int u, int fa = 0) {
	if(!fa) d[u] = 0;
	for(int i = hd[u]; ~ i; i = e[i].nxt) {
		Edge &p = e[i];
		if(p.v != fa) {
			d[p.v] = min(x + 1, d[u] + p.w);
			dfs0(d, p.v, u);
		}
	}
}
void dfs1(int u, int fa = 0) {
	dl[u] = ++ idx; pos[idx] = u;
	for(int i = hd[u]; ~ i; i = e[i].nxt) {
		int v = e[i].v;
		if(v != fa) dfs1(v, u);
	}
	dr[u] = idx;
}
void dfs(int u, int fa = 0) {
	for(int v = 1; v <= n; v ++) {
		if(dis[u][v] <= x && u != v) {
			dp[u][0][v] = 0;
		}
	}
	dp[u][1][u] = w[u] ^ 1; sz[u] = 1;
	for(short i = hd[u]; ~ i; i = e[i].nxt) {
		int v = e[i].v;
		if(v == fa) continue ;
		dfs(v, u);
		for(short s = min(sz[v] + sz[u], (int) m); s >= 0; s --)
			for(short a = 1; a <= n; a ++)
				t[s][a] = n + 1;
		for(short su = min(sz[u], m); su >= 0; su --) {
			for(short sv = min(sz[v], m); sv >= 0; sv --) {
				short mv = n + 1;
				for(int a = dl[v]; a <= dr[v]; a ++) mv = min(mv, dp[v][sv][pos[a]]);
				for(int a = 1; a <= n; a ++) {
					t[su + sv][a] = min((int) t[su + sv][a], dp[u][su][a] + dp[v][sv][a]);
					if(a < dl[v] || a > dr[v]) {
						t[su + sv][pos[a]] = min((int) t[su + sv][pos[a]], dp[u][su][pos[a]] + mv);
					}
				}
			}
		}
		sz[u] += sz[v];
		for(short s = min(sz[u], m); s >= 0; s --)
			for(short a = 1; a <= n; a ++)
				dp[u][s][a] = t[s][a];
	}
}
int main() {
	scanf("%hd%d", &n, &x); clr();
	for(int i = 1; i <= n; i ++) {
		scanf("%hd", w + i);
		m += w[i];
	}
	for(int u, v, w, i = 1; i < n; i ++) {
		scanf("%d%d%d", &u, &v, &w);
		add(u, v, w); add(v, u, w);
	}
	for(int i = 1; i <= n; i ++) dfs0(dis[i], i);
	for(int i = 0; i <= n; i ++)
		for(int j = 0; j <= n; j ++)
			for(int k = 0; k <= n; k ++)
				dp[i][j][k] = n + 1;
	dfs1(1); dfs(1);
	short ans = n + 1;
	for(int i = 1; i <= n; i ++)
		ans = min(ans, dp[1][m][i]);
	printf("%hd\n", ans > n ? -1 : ans);
	return 0;
}

本文作者:hfhongzy

本文链接:https://www.cnblogs.com/hongzy/p/11770957.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   hfhongzy  阅读(305)  评论(0编辑  收藏  举报
编辑推荐:
· Java 中堆内存和栈内存上的数据分布和特点
· 开发中对象命名的一点思考
· .NET Core内存结构体系(Windows环境)底层原理浅谈
· C# 深度学习:对抗生成网络(GAN)训练头像生成模型
· .NET 适配 HarmonyOS 进展
阅读排行:
· 本地部署 DeepSeek:小白也能轻松搞定!
· 如何给本地部署的DeepSeek投喂数据,让他更懂你
· 从 Windows Forms 到微服务的经验教训
· 李飞飞的50美金比肩DeepSeek把CEO忽悠瘸了,倒霉的却是程序员
· 超详细,DeepSeek 接入PyCharm实现AI编程!(支持本地部署DeepSeek及官方Dee
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起