树形dp 笔记

news2024/11/29 0:38:08

树的最长路径

给定一棵树,树中包含 n 个结点(编号1~n)和 n−1 条无向边,每条边都有一个权值。

现在请你找到树中的一条最长路径。

换句话说,要找到一条路径,使得使得路径两端的点的距离最远。

注意:路径中可以只包含一个点。

输入格式

第一行包含整数 n。

接下来 n−1 行,每行包含三个整数 ai,bi,ci,表示点 ai 和 bi 之间存在一条权值为 ci 的边。

输出格式

输出一个整数,表示树的最长路径的长度。

数据范围

1≤n≤10000,
1≤ai,bi≤n,
−1e5≤ci≤1e5

输入样例:
6
5 1 6
1 4 5
6 3 9
2 6 8
6 1 7
输出样例:
22

 边权不为负可以用两次dfs,边权有负就要用这种了

一个点选两个能走得贡献最大的孩子,相加就是能搭在这个点上最长的直径,所有点跑一遍,找最长的那个就行

理论上一个直径上每个点算出来的值都不一样,因为dfs得有个顺序,都是父亲向孩子走得,但每条直径都一定会被算到。

#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define endl '\n'

using namespace std;

typedef pair<int, int> PII;
typedef long long ll;

const int N = 20010;

int pos, n;
int h[N], e[N], w[N], ne[N], idx;
int ans;

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

int dfs(int u, int father)
{
    int dist = 0;
    int d1 = 0, d2 = 0;

    for(int i = h[u]; i != -1; i = ne[i])
    {
        int j = e[i];
        if(j == father)continue;

        int d = dfs(j, u) + w[i];
        dist = max(dist, d);

        if(d > d1)d2 = d1, d1 = d;
        else if(d > d2)d2 = d;
    }

    ans = max(ans, d1 + d2);
    return dist;
}

int main()
{
    IOS
    cin >> n;
    memset(h, -1, sizeof h);
    for(int i = 1; i < n; i ++)
    {
        int a, b, c;
        cin >> a >> b >> c;
        add(a, b, c);
        add(b, a, c);
    }

    dfs(1, -1);

    cout << ans;

    return 0;
}

树的中心

给定一棵树,树中包含 n个结点(编号1~n)和 n−1 条无向边,每条边都有一个权值。

请你在树中找到一个点,使得该点到树中其他结点的最远距离最近。

输入格式

第一行包含整数 n。

接下来 n−1 行,每行包含三个整数 ai,bi,ci,表示点 ai 和 bi 之间存在一条权值为 ci 的边。

输出格式

输出一个整数,表示所求点到树中其他结点的最远距离。

数据范围

1≤n≤10000,
1≤ai,bi≤n,
1≤ci≤1e5

输入样例:
5 
2 1 1 
3 2 1 
4 3 1 
5 1 1
输出样例:
2

 可以延续上一题的思路,尝试枚举一下每个点

最远距离除了往下走的还有一条往上走的,要在两者中取一个最大值

dist数组存往下走的最大值,up数组存往上走的最大值

第一次dfs可以求出dist数组的每个值

然后第二次dfs可以用dist数组的值退出来up的值,根节点up为0,然后就可以按dfs顺序递推出来孩子的up的值了。

#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define endl '\n'

using namespace std;

typedef pair<int, int> PII;
typedef long long ll;

const int N = 20010;

int pos, n;
int h[N], e[N], w[N], ne[N], idx;
int dist[N], up[N];
int ans = 2e9;

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

int dfs(int u, int father)
{
	int res = 0;
	for(int i = h[u]; i != -1; i = ne[i])
	{
		int j = e[i];
		if(j == father)continue;
		
		int d = dfs(j, u) + w[i];
		res = max(res, d);
	}
	dist[u] = res;
	
	return res;
}

void dfs1(int u, int father)
{
	int d1 = 0, d2 = 0;
	for(int i = h[u]; i != -1; i = ne[i])
	{
		int j = e[i];
		if(j == father)continue;
		
		int d = dist[j] + w[i];
		if(d > d1)d2 = d1, d1 = d;
		else if(d > d2)d2 = d;
	}
	
	if(up[u] > d1)d2 = d1, d1 = up[u];
	else if(up[u] > d2)d2 = up[u];
	
	for(int i = h[u]; i != -1; i = ne[i])
	{
		int j = e[i];
		if(j == father)continue;
		
		int res;
		if(dist[j] + w[i] == d1)res = d2;
		else res = d1;
		
		up[j] = res + w[i];
		int tmp = max(up[j], dist[j]);
		ans = min(ans, tmp);
		
		dfs1(j, u);
	}
}

int main()
{
	IOS
	cin >> n;
	memset(h, -1, sizeof h);
	for(int i = 1; i < n; i ++)
	{
		int a, b, c;
		cin >> a >> b >> c;
		add(a, b, c);
		add(b, a, c);
	}
	
	dfs(1, -1);
	dfs1(1, -1);
	
	ans = min(ans, dist[1]);
	cout << ans;
	
	return 0;
}

数字转换

如果一个数 x 的约数之和 y(不包括他本身)比他本身小,那么 x 可以变成 y,y 也可以变成 x。

例如,4 可以变为 3,1 可以变为 7。

限定所有数字变换在不超过 n 的正整数范围内进行,求不断进行数字变换且不出现重复数字的最多变换步数。

输入格式

输入一个正整数 n。

输出格式

输出不断进行数字变换且不出现重复数字的最多变换步数。

数据范围

1≤n≤50000

输入样例:
7
输出样例:
3
样例解释

一种方案为:4→3→1→7。

可以把每个数字看成一个点,求得问题转换为求树的直径

#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define endl '\n'

using namespace std;

typedef pair<int, int> PII;
typedef long long ll;

const int N = 50010;

int n;
vector<int> g[N];
int ans;
bool st[N];
int sum[N];

int get(int x)
{
	int res = 1;
	for(int i = 2; i * i <= x; i ++)
	{
		if(x % i == 0)
		{
			res += i;
			if(x / i != i)res += x / i;
		}
	}
	return res;
}

int dfs(int u, int father)
{
	int d1 = 0, d2 = 0;
	for(auto j : g[u])
	{
		if(j == father)continue;
		int d = dfs(j, u) + 1;
		if(d > d1)d2 = d1, d1 = d;
		else if(d > d2)d2 = d;
	}
	ans = max(ans, d1 + d2);
	return d1;
}

int main()
{
	IOS
	cin >> n;
	for (int i = 1; i <= n; i ++)
        for (int j = 2; j <= n / i; j ++)
            sum[i * j] += i;

    for (int i = 2; i <= n; i ++)
        if (sum[i] < i)
        {
        	g[sum[i]].push_back(i);
        	g[i].push_back(sum[i]);
		}
	
	dfs(1, -1);
	cout << ans;
	
	return 0;
}

二叉苹果树

有一棵二叉苹果树,如果树枝有分叉,一定是分两叉,即没有只有一个儿子的节点。

这棵树共 N 个节点,编号为 1 至 N,树根编号一定为 1。

我们用一根树枝两端连接的节点编号描述一根树枝的位置。

一棵苹果树的树枝太多了,需要剪枝。但是一些树枝上长有苹果,给定需要保留的树枝数量,求最多能留住多少苹果。

这里的保留是指最终与1号点连通。

输入格式

第一行包含两个整数 N 和 Q,分别表示树的节点数以及要保留的树枝数量。

接下来 N−1 行描述树枝信息,每行三个整数,前两个是它连接的节点的编号,第三个数是这根树枝上苹果数量。

输出格式

输出仅一行,表示最多能留住的苹果的数量。

数据范围

1≤Q<N≤100.
N≠1,
每根树枝上苹果不超过 30000个。

输入样例:
5 2
1 3 1
1 4 10
2 3 20
3 5 20
输出样例:
21

有依赖的背包问题的简化版

f[u][j]表示节点u,可分配树枝数量为j,最大值    (j也可理解为背包容量,但也有点不一样,这个容量不包括本身在内)

理解写在注释里了

#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define endl '\n'

using namespace std;

typedef pair<int, int> PII;
typedef long long ll;

const int N = 110, M = 210;

int n, m;
int h[N], e[M], w[M], ne[M], idx;
int f[N][N];

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

void dfs(int u, int father)
{
	for(int i = h[u]; i != -1; i = ne[i])//第i个物品组
	{
		//int j = e[i];
		if(e[i] == father)continue;
		dfs(e[i], u);
		
		for(int j = m; j >= 0; j --)//背包容量
		{
			for(int k = 0; k < j; k ++)//不同决策
			{
				f[u][j] = max(f[u][j], f[u][j - k - 1] + f[e[i]][k] + w[i]);
				//分组背包是物品组里的每个物品体积和价值不同
				//            f[u][i-1][j]    f[u][i-1][j-vk] + w
			}
		}
	}
}

int main()
{
	IOS
	memset(h, -1, sizeof h);
	cin >> n >> m;
	for(int i = 1; i < n; i ++)
	{
		int a, b, c;
		cin >> a >> b >> c;
		add(a, b, c), add(b, a, c);
	}
	
	dfs(1, -1);
	cout << f[1][m];
	
	return 0;
}

战略游戏

鲍勃喜欢玩电脑游戏,特别是战略游戏,但有时他找不到解决问题的方法,这让他很伤心。

现在他有以下问题。

他必须保护一座中世纪城市,这条城市的道路构成了一棵树。

每个节点上的士兵可以观察到所有和这个点相连的边。

他必须在节点上放置最少数量的士兵,以便他们可以观察到所有的边。

你能帮助他吗?

例如,下面的树:

1463_1.jpg.gif

只需要放置 1 名士兵(在节点 1 处),就可观察到所有的边。

输入格式

输入包含多组测试数据,每组测试数据用以描述一棵树。

对于每组测试数据,第一行包含整数 N,表示树的节点数目。

接下来 N 行,每行按如下方法描述一个节点。

节点编号:(子节点数目) 子节点 子节点 …

节点编号从 0 到 N−1,每个节点的子节点数量均不超过 10,每个边在输入数据中只出现一次。

输出格式

对于每组测试数据,输出一个占据一行的结果,表示最少需要的士兵数。

数据范围

0<N≤1500,
一个测试点所有 N 相加之和不超过 300650。

输入样例:
4
0:(1) 1
1:(2) 2 3
2:(0)
3:(0)
5
3:(3) 1 4 2
1:(1) 0
2:(0)
0:(0)
4:(0)
输出样例:
1
2
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define endl '\n'

using namespace std;

typedef pair<int, int> PII;
typedef long long ll;

const int N = 1510;

int n;
vector<int> g[N];
int d[N];
int f[N][2];

void dfs(int u)
{
	f[u][0] = 0;
	f[u][1] = 1;
	for(auto j : g[u])
	{
		dfs(j);
		f[u][0] += f[j][1];
		f[u][1] += min(f[j][0], f[j][1]);
	}
}

int main()
{
	IOS
	while(cin >> n)
	{
		for(int i = 0; i <= n; i ++)
		{
			g[i].clear();
			d[i] = 0;
			f[i][0] = f[i][1] = 0;
		}
		
		int ver1, ver2, num;
		char tmp;
		for(int i = 0; i < n; i ++)
		{
		    cin >> ver1 >>tmp >> tmp >> num >> tmp;
    		for(int i = 0; i < num; i ++)
    		{
    			cin >> ver2;
    			g[ver1].push_back(ver2);
    			d[ver2] ++;
    		}
		}
		
		int root;
		for(int i = 0; i < n; i ++)
		{
			if(!d[i])
			{
				root = i;
				break;
			}
		}
		
		dfs(root);
		cout << min(f[root][0], f[root][1]) << endl;
	}
	
	return 0;
}

皇宫看守

太平王世子事件后,陆小凤成了皇上特聘的御前一品侍卫。

皇宫各个宫殿的分布,呈一棵树的形状,宫殿可视为树中结点,两个宫殿之间如果存在道路直接相连,则该道路视为树中的一条边。

已知,在一个宫殿镇守的守卫不仅能够观察到本宫殿的状况,还能观察到与该宫殿直接存在道路相连的其他宫殿的状况。

大内保卫森严,三步一岗,五步一哨,每个宫殿都要有人全天候看守,在不同的宫殿安排看守所需的费用不同。

可是陆小凤手上的经费不足,无论如何也没法在每个宫殿都安置留守侍卫。

帮助陆小凤布置侍卫,在看守全部宫殿的前提下,使得花费的经费最少。

输入格式

输入中数据描述一棵树,描述如下:

第一行 n,表示树中结点的数目。

第二行至第 n+1 行,每行描述每个宫殿结点信息,依次为:该宫殿结点标号 i,在该宫殿安置侍卫所需的经费 k,该结点的子结点数 m,接下来 m 个数,分别是这个结点的 m 个子结点的标号 r1,r2,…,rm。

对于一个 n 个结点的树,结点标号在 1 到 n 之间,且标号不重复。

输出格式

输出一个整数,表示最少的经费。

数据范围

1≤n≤1500

输入样例:
6
1 30 3 2 3 4
2 16 2 5 6
3 5 0
4 4 0
5 11 0
6 5 0
输出样例:
25
样例解释:

在2、3、4结点安排护卫,可以观察到全部宫殿,所需经费最少,为 16 + 5 + 4 = 25。

本来以为和上一题差不多结果wa了

发现有一种情况是上一题没有的: 

选1、4点也是符合要求的

f[u][0] 不放,但能被父节点看到
f[u][1] 不放,但能被子节点看到
f[u][2] 放 

f[u][0]和f[u][2]都很好像,主要是如何得到f[u][1],能被子节点看到,那就选能被哪个子节点看到,其他点取min(f[u][1], f[u][2]),在所有方案中选个最小值

#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define endl '\n'

using namespace std;

typedef pair<int, int> PII;
typedef long long ll;

const int N = 1510;

int n;
vector<int> g[N];
int w[N], d[N];
int f[N][3];
//f[u][0] 不放,但能被父节点看到
//f[u][1] 不放,但能被子节点看到
//f[u][2] 放 

void dfs(int u)
{
	f[u][0] = 0, f[u][1] = 0, f[u][2] = w[u];
	int sum = 0;
	for(auto j : g[u])
	{
		dfs(j);
		
		f[u][0] += min(f[j][1], f[j][2]);
		sum += min(f[j][1], f[j][2]);
		f[u][2] += min(min(f[j][0], f[j][1]), f[j][2]);
	}
	
	int res = 2e9;
	for(auto j : g[u])
	{
		res = min(res, sum + f[j][2] - min(f[j][1], f[j][2]));
	}
	f[u][1] = res;
}

int main()
{
	IOS
	cin >> n;
	for(int i = 0; i < n; i ++)
	{
		int id, val, num;
		cin >> id >> val >> num;
		w[id] = val;
		for(int j = 0; j < num; j ++)
		{
			int x;
			cin >> x;
			d[x] ++;
			g[id].push_back(x);
		}
	}
	
	int root;
	for(int i = 1; i <= n; i ++)
	{
		if(!d[i])
		{
			root = i;
			break;
		}
	}
	
	dfs(root);
	cout << min(f[root][1], f[root][2]);
	
	return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1450317.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

什么是“感知机”?

感知机&#xff08;神经网络和支持向量机的理论基础&#xff09; 概念&#xff1a;简单来说&#xff0c;感知机就是一个旨在建立一个线性超平面对线性可分的数据集进行分类的线性模型 分类&#xff1a; 单层感知机多层感知机&#xff08; Multi-Layer Perceptron&#xff0c…

DS Wannabe之5-AM Project: DS 30day int prep day18

Q1. What is Levenshtein Algorithm? Levenshtein算法&#xff0c;也称为编辑距离算法&#xff0c;是一种量化两个字符串之间差异的方法。它通过计算将一个字符串转换成另一个字符串所需的最少单字符编辑操作次数来实现。这些编辑操作包括插入、删除和替换字符。Levenshtein距…

Redis -- 数据库管理

目录 前言 切换数据库(select) 数据库中key的数量&#xff08;dbsize&#xff09; 清除数据库&#xff08;flushall flushdb&#xff09; 前言 MySQL有一个很重要的概念&#xff0c;那就是数据库database&#xff0c;一个MySQL里面有很多个database&#xff0c;一个datab…

计算机二级数据库之数据模型(三层相关的结构)

数据模型 模型的概念 模型的介绍模型是对现实世界特征的模拟和抽象&#xff0c; 数据模型的概念&#xff1a; 数据模型是对现实世界中数据特征的抽象&#xff0c;描述的是数据的共性。 数据模型是用来在数据库中抽象、表示和处理现实世界中的数据和信凹。 其相关的共同特…

STM32CubeMX的下载和安装固件库详细步骤

年也过了&#xff0c;节也过了&#xff0c;接下来又要进入紧张的学习中来了。过完年后发现一个问题&#xff0c;就是我之前吃的降压药不太管用&#xff0c;每天的血压只降到了91/140左右&#xff0c;没有到安全范围内&#xff0c;从初三开始换了一种降压药&#xff0c;效果出奇…

问题:内存时序参数 CASLatency 是() #学习方法#微信#微信

问题&#xff1a;内存时序参数 CASLatency 是&#xff08;&#xff09; A&#xff0e;行地址控制器延迟时间 B&#xff0e;列地址至行地址延迟时间 C&#xff0e;列地址控制器预充电时间 D&#xff0e;列动态时间 参考答案如图所示

ArcgisForJS基础

文章目录 0.引言1.第一个ArcgisForJS应用程序1.1.安装部署ArcgisForJS1.2.实现ArcgisForJS应用程序 2.开发与调试工具2.1.集成开发环境2.2.调试工具2.3.Firebug 0.引言 ArcGIS API for JavaScript是一款由Esri公司开发的用于创建WebGIS应用的JavaScript库。它允许开发者通过调…

【数据库】哪些操作会导致索引失效

&#x1f34e;个人博客&#xff1a;个人主页 &#x1f3c6;个人专栏&#xff1a;数据库 ⛳️ 功不唐捐&#xff0c;玉汝于成 目录 前言 正文 结语 我的其他博客 前言 在数据库管理中&#xff0c;索引的有效性对于查询性能至关重要。然而&#xff0c;索引可能会因为各种操…

全战三国与Amadey病毒

一、疑云 某天晚&#xff0c;本人突发奇想从外网上体验一下全战三国&#xff08;全面战争&#xff1a;三国&#xff09;的可玩版本&#xff08;没玩过全战系列&#xff0c;听说三国版是个半成品&#xff0c;打算先体验一下再考虑入正版。国内网站找到的资源&#xff1a;1.53的…

论文阅读 - Non-Local Spatial Propagation Network for Depth Completion

文章目录 1 概述2 模型说明2.1 局部SPN2.2 非局部SPN2.3 结合置信度的亲和力学习2.3.1 传统正则化2.3.2 置信度引导的affinity正则化 3 效果3.1 NYU Depth V23.2 KITTI Depth Completion 参考资料 1 概述 本文提出了一种非局部的空间传播网络用于深度图补全&#xff0c;简称为…

语言与科技创新(大语言模型对科技创新的影响)

1.科技创新中的语言因素 科技创新中的语言因素至关重要&#xff0c;具体体现在以下几个方面&#xff1a; 科技文献交流&#xff1a; 英语作为全球科学研究的通用语言&#xff0c;极大地推动了科技成果的国际传播与合作。科学家们在发表论文、报告研究成果时&#xff0c;大多选…

(17)Hive ——MR任务的map与reduce个数由什么决定?

一、MapTask的数量由什么决定&#xff1f; MapTask的数量由以下参数决定 文件个数文件大小blocksize 一般而言&#xff0c;对于每一个输入的文件会有一个map split&#xff0c;每一个分片会开启一个map任务&#xff0c;很容易导致小文件问题&#xff08;如果不进行小文件合并&…

Mac终端远程访问Linux

以ubuntu为例 一、查看ubuntu的ip地址 1、下载net-tools localhostubuntu-server:~$ sudo apt install net-tools 2、查看ip地址 localhostubuntu-server:~$ ifconfig ubuntu需要下载net-tools才能使用ifconfig localhostubuntu-server:~$ sudo apt install net-tools 二…

问题:下列不属于影响职业选择的内在因素是()。 #微信#微信

问题&#xff1a;下列不属于影响职业选择的内在因素是&#xff08;&#xff09;。 A.健康 B.个性特征 C.性别 D.家庭的影响 参考答案如图所示

算法刷题day13

目录 引言一、蜗牛 引言 今天时间有点紧&#xff0c;只搞了一道题目&#xff0c;不过确实搞了三个小时&#xff0c;才搞完&#xff0c;主要是也有点晚了&#xff0c;也好累啊&#xff0c;不过也还是可以的&#xff0c;学了状态DP&#xff0c;把建图和spfa算法熟悉了一下&#…

[嵌入式AI从0开始到入土]14_orangepi_aipro小修补含yolov7多线程案例

[嵌入式AI从0开始到入土]嵌入式AI系列教程 注&#xff1a;等我摸完鱼再把链接补上 可以关注我的B站号工具人呵呵的个人空间&#xff0c;后期会考虑出视频教程&#xff0c;务必催更&#xff0c;以防我变身鸽王。 第1期 昇腾Altas 200 DK上手 第2期 下载昇腾案例并运行 第3期 官…

openGauss学习笔记-221 openGauss性能调优-确定性能调优范围-分析作业是否被阻塞

文章目录 openGauss学习笔记-221 openGauss性能调优-确定性能调优范围-分析作业是否被阻塞221.1 操作步骤 openGauss学习笔记-221 openGauss性能调优-确定性能调优范围-分析作业是否被阻塞 数据库系统运行时&#xff0c;在某些业务场景下查询语句会被阻塞&#xff0c;导致语句…

备战蓝桥杯---图论之最短路dijkstra算法

目录 先分个类吧&#xff1a; 1.对于有向无环图&#xff0c;我们直接拓扑排序&#xff0c;和AOE网类似&#xff0c;把取max改成min即可。 2.边权全部相等&#xff0c;直接BFS即可 3.单源点最短路 从一个点出发&#xff0c;到达其他顶点的最短路长度。 Dijkstra算法&#x…

vmware workstation群晖虚拟机vmdk文件导出

为了防止群晖虚拟机中整个挂掉&#xff0c;里面的文件导不出来&#xff0c;尝试直接从vmdk中获取内容。 1、想采用diskgenius去读取文件&#xff0c;发现volume1是空的。只能读取群晖的系统文件。 2、选择另一个linux系统的虚拟机&#xff0c;选择对应的vmdk 3、如果有文件管理…

Python slice函数

在Python编程中&#xff0c;slice&#xff08;切片&#xff09;操作是一种强大且灵活的方式&#xff0c;用于从序列&#xff08;如列表、元组、字符串等&#xff09;中获取子序列。通过切片操作&#xff0c;可以轻松地提取序列中的一部分&#xff0c;进行遍历、修改、复制等操作…