【树的直径】洛谷_3629 [APIO2010]巡逻

2024-01-30 04:32

本文主要是介绍【树的直径】洛谷_3629 [APIO2010]巡逻,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

题意

有一颗树,要在其中加入 K ( k ≤ 2 ) K(k\leq 2) K(k2)条边,使得本来遍历这颗树要经过的边数最少,同时加入的边一定要正好走过 1 1 1次。

思路

K = 1 K=1 K=1时,显然是在树的直径的两个点之间连一条边,因为这样可以少走一次直径,而直径又是最长的。
K = 2 K=2 K=2时,新建的边如果与之前的边没有环重叠的话也是和 K = 1 K=1 K=1的方法一样。如果有重叠的话,那么要正好走过一次新建的边,我们重复的边就要都多走一次。
综上所述,可以这样做:
1 ) 1) 1)先求一次树的直径,记为 D 1 D_1 D1,然后把直径上的边取反。
2 ) 2) 2)再求一次直径,记为 D 2 D_2 D2
答案为 2 ( N − 1 ) − ( D 1 − 1 ) − ( D 2 − 1 ) 2(N-1)-(D_1-1)-(D_2-1) 2(N1)(D11)(D21),如果我们取到重复的边,因为它是负的,根据初中数学,可以知道它会加回来。

代码

#include<cstdio>
#include<cstring>
#include<algorithm>struct node{int to, next, v;
}e[200001];
int N, K, tot = 1, l, r, d;
int head[100001], pre[100001], v[100001], f[100001];void add(int x, int y) {e[++tot].to = y;e[tot].next = head[x];e[tot].v = 1;head[x] = tot;
}void dfs1(int p, int fa, int w) {if (w >= d) {d = w;l = p;}for (int i = head[p]; i; i = e[i].next) {if (e[i].to != fa)dfs1(e[i].to, p, w + e[i].v);}
}void dfs2(int p, int fa, int w) {if (w >= d) {d = w;r = p;}for (int i = head[p]; i; i = e[i].next) {if (e[i].to != fa) {pre[e[i].to] = p;dfs2(e[i].to, p, w + e[i].v);}}
}void dfsD() {//dfs求树的直径d = 0;dfs1(1, 0, 0);d = 0;dfs2(l, 0, 0);
}void change(int p) {//暴力回溯改边if (p == l) return;for (int i = head[p]; i; i = e[i].next) {if (e[i].to == pre[p]) {e[i].v = -1;e[i ^ 1].v = -1;change(e[i].to);}}
}void dp(int x) {v[x] = 1;for (int i = head[x]; i; i = e[i].next) {if (v[e[i].to]) continue;dp(e[i].to);d = std::max(d, f[x] + f[e[i].to] + e[i].v);f[x] = std::max(f[x], f[e[i].to] + e[i].v);}
}int main() {scanf("%d %d", &N, &K);for (int i = 1, a, b; i < N; i++) {scanf("%d %d", &a, &b);add(a, b);add(b, a);}dfsD();if (K == 1) {printf("%d", 2 * N - 1 - d);return 0;} else {int s = 2 * N - d;change(r);d = 0;dp(1);//边权有负所以用树形dpprintf("%d", s - d);return 0;}
}

这篇关于【树的直径】洛谷_3629 [APIO2010]巡逻的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/659111

相关文章

zoj3820(树的直径的应用)

题意:在一颗树上找两个点,使得所有点到选择与其更近的一个点的距离的最大值最小。 思路:如果是选择一个点的话,那么点就是直径的中点。现在考虑两个点的情况,先求树的直径,再把直径最中间的边去掉,再求剩下的两个子树中直径的中点。 代码如下: #include <stdio.h>#include <string.h>#include <algorithm>#include <map>#

高精度计算(代码加解析,洛谷p1601,p1303)除法待更新

目录 高精度加法 高精度减法 高精度乘法 高精度加法 我们知道在c++语言中任何数据类型都有一定的表示范围。当两个被加数很大时,正常加法不能得到精确解。在小学,我们做加法都采用竖式方法。那么我们也只需要按照加法进位的方式就能得到最终解。 8 5 6+ 2 5 5-------1 1 1 1 加法进位: c[i] = a[i] + b[i];if(c[i] >=

洛谷 凸多边形划分

T282062 凸多边形的划分 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 先整一个半成品,高精度过两天复习一下补上 #include <iostream>#include <algorithm>#include <set>#include <cstring>#include <string>#include <vector>#include <map>

能量项链,洛谷

解释:  环形dp问题还是考虑将环拉直,可以参考我上一篇文章:环形石子合并 [2 3 5 10 2] 3 5 10 将环拉直,[]内是一个有效的区间,可以模拟吸收珠子的过程,         如[2 3 5] <=>(2,3)(3,5)    2是头,3是中间,5是尾 len >= 3:因为最后[2 10 2]是最小的可以合并的有效区间 len <= n + 1因为[2 3

洛谷P5490扫描线

0是最小的数字,将一个线段看成一个区间,对于一个矩形,从下扫到上,入边为1,而出边为-1,意思是将这个区间上的所有点加1(区间修改).把线段表示为Line[i],其中记录了l,r,h,tag,左右端点,高度,入边还是出边(1或-1) 那么每次区间修改后不为0的区间它的值可能是1,2,3或者是其它数字,这不好统计,可以将它转化一下,0是不是表示没有被覆盖过的地方,我们只要统计0的个数然后用总长减去

挤牛奶洛谷uasco

题目描述 三个农民每天清晨5点起床,然后去牛棚给3头牛挤奶。第一个农民在300秒(从5点开始计时)给他的牛挤奶,一直到1000秒。第二个农民在700秒开始,在 1200秒结束。第三个农民在1500秒开始2100秒结束。期间最长的至少有一个农民在挤奶的连续时间为900秒(从300秒到1200秒),而最长的无人挤奶的连续时间(从挤奶开始一直到挤奶结束)为300秒(从1200秒到1500秒)。

poj 1849 Two(树形dp求直径)

树的直径:一棵树中两个点间的最长距离。 Description The city consists of intersections and streets that connect them.  Heavy snow covered the city so the mayor Milan gave to the winter-service a list of streets that ha

洛谷刷题(7)

P8738 [蓝桥杯 2020 国 C] 天干地支 题目描述 古代中国使用天干地支来记录当前的年份。 天干一共有十个,分别为:甲(jiǎ)、乙(yǐ)、丙(bǐng)、丁(dīng)、戊 (wù)、己(jǐ)、庚(gēng)、辛(xīn)、壬(rén)、癸(guǐ)。 地支一共有十二个,分别为:子(zǐ)、丑(chǒu)、寅(yín)、卯(mǎo)、辰(chén)、巳(sì)、午(wǔ)、

C++ 洛谷 哈希表(对应题库:哈希,hash)习题集及代码

马上就开学了,又一个卷季,不写点东西怎么行呢?辣么,我不准备写那些dalao们都懂得,熟练的,想来想去,最终还是写哈希表吧!提供讲解&题目&代码解析哦! 奉上题目链接: 洛谷题目 - 哈希,hash 1、哈希、哈希表(hash)简介 哈希(Hash)是一种将任意长度的输入映射为固定长度输出的算法。哈希函数的输出值称为哈希值或散列值。哈希函数具有以下特性: 确定性:对于相同的输入

POJ 1985 Cow Marathon(树的直径)

题目链接 题意:给出一棵树,求出这个树的直径 解答:任选一点进行dfs,会找到一个最远点s,在以这个最远点s进行dfs,会找到一个最远点是t,那么s-t就是树的直径。 //#include<bits/stdc++.h>#include<cstdio>#include<algorithm>#include<vector>#include<cstring>using namespace