首页 > 其他分享 >洛谷 P8595 「KDOI-02」一个网的路 蓝 题解

洛谷 P8595 「KDOI-02」一个网的路 蓝 题解

时间:2022-10-27 12:14:07浏览次数:93  
标签:02 炸掉 洛谷 int 题解 sum son 儿子 代价

定义

树形 \(DP\),这个挺明显的,我认为 \(DP\) 让读者理解的最重要的一步是:定义。

所以我先详细说明 \(f\) 数组的定义,至于为什么这么定义后面再讲。

\(f_{u, type}\),其中 \(type=0,1,2\)

\(f_{u,0}\) 表示:在原森林中,以 \(u\) 为根节点的子树变成链的最小代价,其中 \(u\) 必须被炸掉。

\(f_{u,1}\) 表示:在原森林中,以 \(u\) 为根节点的子树变成链的最小代价,其中 \(u\) 必须不被炸掉,且 \(u\) 最多有一个儿子。

\(f_{u,2}\) 表示:在原森林中,以 \(u\) 为根节点的子树变成链的最小代价,其中 \(u\) 必须不被炸掉,且 \(u\) 最多有两个儿子。

为什么这样定义

首先,一个节点炸或者不炸,是会影响它向父亲节点转移的,所以必须分类:炸掉、不炸掉。

而一个点如果不被炸掉,那么它应该有几个儿子呢?可以一个都没有,所有儿子都被炸掉;可以有一个或者两个,对应链的情况。如果有超过三个儿子,那么不可能形成链。

所以就先这么定义,看看能不能转移。

状态转移方程

类型 0

考虑 \(f_{u,0}\) 的状态转移方程。

首先,\(u\) 点必须被炸掉,所以代价加一

其次,炸了 \(u\) 之后,\(u\) 有几个儿子就需要再连几条边,因为最后要形成链,所以代价加上 \(u\) 的儿子数量

最后,你还需要把儿子节点的信息传递上来,由于炸了 \(u\) 之后,\(u\) 和它的所有儿子都不联通,那么 \(u\) 的儿子的类型是几并不重要,那么代价还需要加上 \(\sum\limits_{v\in son_u } \min(f_{v,0}-1, f_{v,1}, f_{v,2})\)

为什么有一项是 \(f_{v,0}-1\)?为啥要减一?因为在之前遍历到 \(v\) 的时候,\(u,v\) 之间的边被炸了一次;现在炸 \(u\) 的时候,\(u,v\) 之间的边又被炸了一次,重复了。

我们令 \(d_u\) 表示 \(u\) 的儿子的数量,那么 \(f_{u,0} = \sum\limits_{v\in son_u } \min(f_{v,0}-1, f_{v,1}, f_{v,2}) + d_u + 1\)

类型 1

首先,\(u\) 不能被炸,如果让 \(u\) 只剩下 \(1\) 个儿子,我们可以来一个简单的容斥。

先把 \(u\) 的所有儿子都炸掉,然后选择一个儿子恢复,当然有可能不选,因为是最多一个儿子

考虑第一步,代价很简单,为 \(\sum\limits_{v\in son_u} f_{v,0}\)

对于第二步,我们要挑选一个 \(v\),先将代价减去 \(f_{v,0}\) ,表示我不炸这个 \(v\) 了,让它留着做 \(u\) 的儿子;再将代价加上 \(f_{v,1}\),表示将信息转移到父亲,至于为什么和 \(f_{v,2}\) 没有关系,后面再说。

所以儿子都炸完之后,我们要找一个最大的 \(f_{v,0} - f_{v,1}\),让原来的代价减去它,即为最终代价,如果所有的 \(f_{v,0} - f_{v,1}\) 都小于零,那就不要儿子了,因为要上儿子只能使代价变大。

为什么和 \(f_{v,2}\) 没有关系?因为不可能由 \(f_{v,2}\) 转移过来,因为一个点有一个儿子,而这个儿子又有两个儿子,那么肯定不可能组成一条链,如果还不懂的话,我画个图:

如果你可以什么操作都不做把它画成一条链我就当场认爹

所以状态转移方程为:\(f_{u,1} = \sum\limits_{v\in son_u} f_{v,0} - \max(0, \max_{v\in son_u}(f_{v,0} - f_{v,1}))\)

类型 2

这个简单,在类型 1 的基础上再减去一个次大的大于零的 \(f_{v,0} - f_{v,1}\) 即可。

即 \(f_{u,2} = f_{u,1} - \max(0, SEC_{v \in son_u}(f_{v,0} - f_{v,1}))\) (这里的 \(SEC\) 指第二大的数)

整理

\(f_{u,0} = \sum\limits_{v\in son_u } \min(f_{v,0}-1, f_{v,1}, f_{v,2}) + d_u + 1\)

\(f_{u,1} = \sum\limits_{v\in son_u} f_{v,0} - \max(0, \max_{v\in son_u}(f_{v,0} - f_{v,1}))\)

\(f_{u,2} = f_{u,1} - \max(0, SEC_{v \in son_u}(f_{v,0} - f_{v,1}))\)

求答案

首先对于每一棵树,我们的答案很显然:为 \(\min(f_{u,0}, f_{u,1}, f_{u,2})\),但这是一个森林,所以我们还需要加上一些边让整森林变成一颗大树,加边数量为:\(n-1-m\),即总共需要 \(n-1\) 条边,题目给了 \(m\) 条边,那么还需要再加上 \(n-1-m\) 条边

所以 \(Ans = \sum\limits_{u\in root} \min(f_{u,0}, f_{u,1}, f_{u,2}) + n - 1 - m\)

code

#include <iostream>
#include <cstring>

using namespace std;

const int N = 2e6 + 10, M = 2 * N;

int n, m, ans;
int h[N], e[M], ne[M], idx;
int d[N], f[N][3];
bool vis[N];

int read()
{
	int s = 0, w = 1;
	char c = getchar();
	while (c < '0' || c > '9')
	{
		if (c == '-') w = -1;
		c = getchar();
	}
	while (c >= '0' && c <= '9')
	{
		s = s * 10 + c - '0';
		c = getchar();
	}
	return s * w;
}

void add(int a, int b)
{
	e[idx] = b;
	ne[idx] = h[a];
	h[a] = idx ++ ;
	return;
}

void dfs(int u)
{
	vis[u] = true;
	int fir = 0, sec = 0;
	for (int i = h[u]; ~i; i = ne[i])
	{
		int ver = e[i];
		if (vis[ver]) continue;
		dfs(ver); 
		int delta = f[ver][0] - f[ver][1];
		if (delta > fir) sec = fir, fir = delta;
		else if (delta > sec) sec = delta;
		f[u][0] += min(f[ver][0] - 1, min(f[ver][1], f[ver][2]));
		f[u][1] += f[ver][0];
	}
	f[u][0] += d[u] + 1;
	f[u][1] -= fir;
	f[u][2] = f[u][1] - sec;
	return;
}

int main()
{
	n = read(), m = read();
	ans = (n - 1) - m;
	memset(h, -1, sizeof h);
	for (int i = 1; i <= m; i ++ )
	{
		int a, b;
		a = read(), b = read();
		add(a, b);
		add(b, a);
		d[a] ++ ;
		d[b] ++ ;
	}
	for (int i = 1; i <= n; i ++ )
	{
		if (!vis[i]) 
		{
			dfs(i);
			ans += min(f[i][0], min(f[i][1], f[i][2]));
		}
	}
	cout << ans << endl;
	return 0;
}

/*
   _____
  /     \
 /  'v'  \
/  __O__  \
\____|____/
*/

完结撒花!

标签:02,炸掉,洛谷,int,题解,sum,son,儿子,代价
From: https://www.cnblogs.com/LittleMoMol-kawayi/p/solution_LuoGu_P8595.html

相关文章

  • 2022.10.27每日一题
    DaimayuanOnlineJudge-跳跳题目描述平面上给定了一些整点(横纵坐标均为整数的点),被称为“魔法阵”。魔法少女派派想要在各魔法阵之间传送,每一次传送,她将使用下面的方式:......
  • 2021-08-14美团算法面试题【数组实现二分、三数和、求n进制】
    一、二分查找publicstaticintsearch(int[]nums,inttarget){intleft=0,right=nums.length-1;while(left<=right){intmid=(l......
  • 2021字节跳动秋招整理牛客网---Java后端提前批面试
    一、字节提前批java后端一面1.1你说你用了RPC远程调用,讲讲原理是怎么样的RPC(RemoteProcedureCall)远程调用,通过某种手段,协议,约定调用非本地服务RPC框架作为架构微服......
  • 代码随想录 KMP算法,实现 strStr()(LeetCode 028)和重复的子字符串(LeetCode 459)
    KMP算法前缀表:记录下标i之前(包括i)的字符串中,有多大长度的相同前缀后缀。前缀是指不包含最后一个字符的所有以第一个字符开头的连续子串。后缀是指不包含第一个字符的所......
  • 安全周报2022-10-20
    PleaseSubscribeWechatOfficialAccount:信安科研人,获取更多的原创安全资讯每周新闻CISA通告ADVANTECH和日立工业电器的存在严重缺陷美国网络安全和基础设施安全局(CIS......
  • 以商业视角解析数据驱动,神策 2022 数据驱动大会发布全新数字化闭环产品方案
    10月26日,神策2022数据驱动大会在北京丽亭华苑酒店举办。大会以“用科学重塑营销”为主题,商业模式创新领域知名作家亚历山大·奥斯特瓦德(AlexanderOsterwalder)、神策数......
  • 2022年10月27日
      人生中的很多路,都要自己去走,很多人都靠不住,凡事靠自己才能顺顺利利,勤勉才是真理!  毕淑敏说:生活就是泥沙俱下,鲜花与荆棘并存。  这一路走过来不容易,跌跌撞......
  • Adobe2023全家桶安装教程
    关于Adobe2023套装介绍:北京时间2022年10月18日,Adobe公司发布了全新系列的套件,全称是AdobeCreativeCloud2023,包括了PS、AE、PR、AU、LR、DW、ID等数十款专业领域的应......
  • 20201318李兴昕第六章学习笔记
    第五章:定时器及时钟服务知识点归纳总结:本章讲述了信号和信号处理;介绍了信号和中断的统一处理,有助于从正确的角度看待信号;将信号视为进程中断,将进程从正常执行转移到......
  • IDEA删除子项目后,在重建时出现的问题解决方法
    IDEA删除子项目后,在重建时出现的问题解决方法每次删除子项目后都会出现这样的问题发现java,resource里面没有变色,当你对pom,文件里面的内容进行添加依赖是,在点击idea—>f......