ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

CF375E Red and Black Tree

2021-07-29 08:31:06  阅读:214  来源: 互联网

标签:记录 黑点 交换 Tree int Black CF375E include dp


一、题目

点此看题

二、解法

交换操作真的很难做,而且距离是难以记录的,所以套路的 \(dp\) 方法是行不通的。

对于交换操作有一个神奇的转化:由于交换是全局任意交换的,我们考虑记录已经用到的黑点个数,如果用到的黑点个数不超过原有的黑点个数那么就是一种合法的操作,然后我们不记录距离去记录解决该点问题的点。

设 \(dp[u][i][t]\) 表示以 \(u\) 为根的子树中,有 \(i\) 个关键点,其中解决 \(u\) 问题的节点在 \(t\)(我们称 \(u\) 使用 \(t\))的最小交换次数。转移考虑合并子树,为了保证转移的正确性,我们要在把 \(t\) 合并到 \(u\) 上的时候考虑 \(t\) 为黑点的代价

  • 考虑合并子树,\(dp[u][i+j][t]\leftarrow dp[u][i][t]+dp[v][j][t]\),也就是它们共同使用一个黑点 \(t\),那么如果 \(t\) 在 \(u\) 子树中 \(t\) 为黑点的代价就会被考虑到。
  • 如果 \(u,v\) 所使用的黑点不同,那么 \(v\) 使用的节点一定要在其子树中,所以设 \(mn=\min dp[v][j][t]\),那么如果 \(t\not\in v\) 的子树,那么 \(dp[u][i+j][t]\leftarrow dp[u][i][t]+mn\)

初始化:\(dp[u][1][u]=1-a[u]\),如果 \(d(u,v)\leq x\),那么 \(dp[u][0][v]=0\)

因为第二维的是树背包,所以总时间复杂度 \(O(n^3)\),要用 \(\tt short\) 来卡空间。

三、总结

交换操作是难做的,但是我们用记录状态的方法解决了此问题(用黑点个数描述合法交换),所以记录状态竟然能解决操作的问题!

本题还有一个转化是记录每个点使用的点,但是需要注意何时考虑代价,所以这题是代价延后计算,这十分适用于全局操作问题中。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std; 
const int M = 501;
int read()
{
	int x=0,f=1;char c;
	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
	return x*f;
}
int n,m,tot,a[M],f[M],x,cnt,pd[M][M],dfn[M],sz[M];
short dp[M][M][M],g[M][M],ans=0x3f3f;
struct edge
{
	int v,c,next;
}e[2*M];
short min(short a,short b) {return a<b?a:b;}
void work(int u,int rt,int w)
{
	pd[rt][u]=1;
	for(int i=f[u];i;i=e[i].next)
	{
		int v=e[i].v,c=e[i].c;
		if(!pd[rt][v] && w+c<=x)
			work(v,rt,w+c);
	}
}
void pre(int u,int fa)
{
	dfn[u]=++cnt;
	for(int i=f[u];i;i=e[i].next)
		if(e[i].v^fa) pre(e[i].v,u);
}
void dfs(int u,int fa)
{
	sz[u]=1;
	dp[u][1][dfn[u]]=!a[u];
	for(int v=1;v<=n;v++)
		if(u!=v && pd[u][v]) dp[u][0][dfn[v]]=0;
	for(int w=f[u];w;w=e[w].next)
	{
		int v=e[w].v;
		if(v==fa) continue;
		dfs(v,u);
		for(int i=0;i<=sz[u];i++)
			for(int t=1;t<=n;t++)
				g[i][t]=dp[u][i][t],dp[u][i][t]=0x3f3f;
		for(int i=0;i<=sz[u];i++)
			for(int j=0;j<=sz[v] && i+j<=m;j++)
			{
				int mn=*min_element(dp[v][j]+dfn[v],dp[v][j]+dfn[v]+sz[v]);
				for(int t=1;t<=n;t++)
				{
					dp[u][i+j][t]=min(dp[u][i+j][t],g[i][t]+dp[v][j][t]);
					if(t<dfn[v] || t>=dfn[v]+sz[v])
						dp[u][i+j][t]=min(dp[u][i+j][t],g[i][t]+mn);
				}
			}
		sz[u]+=sz[v];
	}
}
signed main()
{
	n=read();x=read();
	for(int i=1;i<=n;i++)
		a[i]=read(),m+=a[i];
	for(int i=1;i<n;i++)
	{
		int u=read(),v=read(),c=read();
		e[++tot]=edge{v,c,f[u]},f[u]=tot;
		e[++tot]=edge{u,c,f[v]},f[v]=tot;
	}
	pre(1,0);
	for(int i=1;i<=n;i++)
		work(i,i,0);
	memset(dp,0x3f,sizeof dp);
	dfs(1,0);
	for(int i=0;i<=m;i++)
		for(int j=1;j<=n;j++)
			ans=min(ans,dp[1][i][j]);
	if(ans==0x3f3f) puts("-1");
	else printf("%d\n",ans);
}

标签:记录,黑点,交换,Tree,int,Black,CF375E,include,dp
来源: https://www.cnblogs.com/C202044zxy/p/15073475.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有