[APIO2010] 算法竞赛竞赛经典 巡逻
题目描述
在一个地区有 n 个村庄,编号为1,2,…,n。
有 n-1 条道路连接着这些村庄,每条道路刚好连接两个村庄,从任何一个村庄,都可以通过这些道路到达其他任一个村庄。
每条道路的长度均为1个单位。
为保证该地区的安全,巡警车每天都要到所有的道路上巡逻。
警察局设在编号为1的村庄里,每天巡警车总是从警局出发,最终又回到警局。
为了减少总的巡逻距离,该地区准备在这些村庄之间建立 K 条新的道路,每条新道路可以连接任意两个村庄。
两条新道路可以在同一个村庄会合或结束,甚至新道路可以是一个环。
因为资金有限,所以 K 只能为1或2。
同时,为了不浪费资金,每天巡警车必须经过新建的道路正好一次。
编写一个程序,在给定村庄间道路信息和需要新建的道路数的情况下,计算出最佳的新建道路的方案,使得总的巡逻距离最小。
输入格式
第一行包含两个整数 n 和 K。
接下来 n-1 行每行两个整数 a 和 b,表示村庄 a 和 b 之间有一条道路。
输出格式
输出一个整数,表示新建了 K 条道路后能达到的最小巡逻距离。
数据范围
\(3 \le n \le 100000\),
\(1 \le K \le 2\),
\(1 \le a,b \le n\)
输入样例:
8 1
1 2
3 1
3 4
5 3
7 5
8 5
5 6
输出样例:
11
解题报告
题意理解
有一颗\(n-1\)个节点的树,警察局设在根节点,两个节点之间的距离固定是\(1\),现在要求所有的节点都要至少访问一遍,可以访问多次.
猪八戒警察是个不愿意浪费多余时间的人死胖子,时间要花在睡觉吃饭上面,所以他只想要走最短的路.为什么胖,就是因为懒,贪吃
要致富先修路,于是上面派发了巨款修路,这笔巨款,居然可以添加一条路,或者两条路.巨款好多啊,全被猪八戒买东西吃掉了
不过有要求,那就是新修建的路,只准走一次,因为豆腐渣工程,不安全.
解题思路
题目分析
一道题目中,条件性质都是一座座宝藏,必须深入挖掘.才能成为yxc老师一般的人生赢家
- 题目的核心是什么?
偷懒走最少的路
- 换句话表示是什么?
不要走最长的路
- 什么是最长的路?
树的直径
- 树的直径是什么?
一棵树上,最远的两个点,他们的距离.
- 添加路径有什么效果?
使得两个点的最短距离变成\(1\).
- 当只能增加一条新的路径的时候,我们怎么最大化利润?
找到树的直径的两个端点,在他们中间添加一条新路径.
样例分析
这是我们样例1的模型.
让我们来求一下这棵树的树的直径
假如说我们将这条直径的两个端点相连接的话,我们最多可以优惠多少路径长度呢?
性质是什么,就是从一个特殊例子,变化成为一个通解公式
性质总结
因此我们通过上面的每一步,得到了如下的这些重要性质.
- 刚开始我们一共要走的长度是:
n是这棵树上的节点个数
\]
因为对于每一个点而言,我们必须要走两次. (你可以认为就像是DFS搜索一样)
第一次访问这个点,也就是进入这个点.
第二次访问这个点,也就是离开这个点.
- 假如说我们之前的树,它的树的直径长度是\(L\),那么经过我们第一轮路径增加过后.
也就是2*(n-1)-L+1
\]
因为我们不必再走一遍树的直径了,所以我们减少了\(L\)的长度.
但是我们增加了一条边,所以我们增加了\(1\)的长度.
总而言之,言而总之,这就是我们对于增加一条边的性质总结.
重点思考
这道题目,不仅仅要让我们增加一条边,还有增加第二条边的可能.
假如说我们没有第一条边的建立,那么现在我们增加第二条边,其实所有步骤都是和上面建立第一条边是一样的.
- 第一条边建立后的影响
我们知道,树之所以是树,是因为它不会出现环.
但是现在一条边的建立,环它出现了.是他,是他,就是他,我们的小英雄一组环
因为出现了环,所以我们现在不能保证一个点,那就是
第二条边构造的B环会不会和第一条边构造的A环,有重叠部分.
- 假如说没有重叠部分
如果说没有重叠,那么第一条边和第二条边各自为政,井水不犯河水,我们可以看作是两次第一条边.
只需要把第一次步骤,重复两遍即可.
- 如果有重叠部分
我们现在要明确一点,为什么我们添加边,可以使得路径缩小?
因为对于树的直径上的所有点,我们只需要进入一次,并不需要再离开一次了.
- 但是重叠部分会导致什么呢?
对于一个节点而言,它是重叠部分上的点.
第一次,它被减少掉了一条边.
第二次,它再次被减少了一条边.
请问它还会被访问吗?
答案是不可能!因为我们一个节点,最多访问两次,而你减少了两次.
所以此时,我们的这些重叠部分上的点,从只需要访问一次,变成了需要访问两次.
因为我们必须去访问这些点,而访问了一次,又必须再离开一次,于是就是访问两次
算法流程
在最初的树上,求出树的直径\(L1\),然后将这条路径上的所有边权统统取反.
\[1变成-1
\]我们再求一次树的直径\(L2\).
答案就是
\[2 \times (n-1)-(L1-1)-(L2-1) \\\\
= 2 \times (n-1)-L1+1-L2+1
\]
假如说\(L2\)和\(L1\)有重叠部分.
那么当我们
\]
的时候,我们就会发现,重叠的部分变成了只需要经过一次.
然后
\]
相当于把重叠部分相加回来了.
此时变成了经过了两次.
假如说没有重叠部分,那么1,-1都不会有影响,反正我们不会经过这些边.
代码解析
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+20;
int n,k;
struct Edge
{
int ver[2*N],edge[2*N],Next[2*N],head[N],dis[N],pre[N],f[N],v[N],tot,p,i,x,y,z;
queue<int> q;
void init()
{
memset(head,0,sizeof(head));
tot=1;
}
void add_edge(int a,int b,int c)
{
edge[++tot]=b;
ver[tot]=c;
Next[tot]=head[a];
head[a]=tot;
}
int bfs(int s)
{
int i,x,y;
memset(dis,0x3f,sizeof(dis));
q.push(s);
dis[s]=pre[s]=0;
while(q.size())
{
x=q.front();
q.pop();
for(i=head[x]; i; i=Next[i])
if(dis[edge[i]]==0x3f3f3f3f)
dis[edge[i]]=dis[x]+ver[i],pre[edge[i]]=i,q.push(edge[i]);
}
for(x=y=1; x<=n; x++)
if(dis[x]>dis[y])
y=x;
return y;
}
int diam()
{
p=bfs(1);
p=bfs(p);
return dis[p];
}
void change()
{
for(; pre[p]; p=edge[pre[p]^1]) ver[pre[p]]=ver[pre[p]^1]=-1;
}
void dp(int x)
{
v[x]=1;
for(int i=head[x]; i; i=Next[i])
if(!v[edge[i]])
{
dp(edge[i]);
y=max(y,f[edge[i]]+f[x]+ver[i]);
f[x]=max(f[x],f[edge[i]]+ver[i]);
}
}
void work()
{
x=diam(),y=0,z=1;
if(k==2)
change(),dp(1),z=2;
printf("%d\n",2*(n-1)-x-y+z);
}
} g1;
int main()
{
// freopen("stdin.in","r",stdin);
scanf("%d%d",&n,&k);
g1.init();
for(int i=1; i<n; i++)
{
int a,b;
scanf("%d%d",&a,&b);
g1.add_edge(a,b,1);
g1.add_edge(b,a,1);
}
g1.work();
return 0;
}
[APIO2010] 算法竞赛竞赛经典 巡逻的更多相关文章
- (Step1-500题)UVaOJ+算法竞赛入门经典+挑战编程+USACO
http://www.cnblogs.com/sxiszero/p/3618737.html 下面给出的题目共计560道,去掉重复的也有近500题,作为ACMer Training Step1,用1年 ...
- [刷题]算法竞赛入门经典 3-12/UVa11809
书上具体所有题目:http://pan.baidu.com/s/1hssH0KO 题目:算法竞赛入门经典 3-4/UVa11809:Floating-Point Numbers 代码: //UVa11 ...
- [刷题]算法竞赛入门经典 3-10/UVa1587 3-11/UVa1588
书上具体所有题目:http://pan.baidu.com/s/1hssH0KO 题目:算法竞赛入门经典 3-10/UVa1587:Box 代码: //UVa1587 - Box #include&l ...
- [刷题]算法竞赛入门经典 3-7/UVa1368 3-8/UVa202 3-9/UVa10340
书上具体所有题目:http://pan.baidu.com/s/1hssH0KO 都是<算法竞赛入门经典(第二版)>的题目,标题上没写(第二版) 题目:算法竞赛入门经典 3-7/UVa13 ...
- [刷题]算法竞赛入门经典 3-4/UVa455 3-5/UVa227 3-6/UVa232
书上具体所有题目:http://pan.baidu.com/s/1hssH0KO 题目:算法竞赛入门经典 3-4/UVa455:Periodic Strings 代码: //UVa455 #inclu ...
- [刷题]算法竞赛入门经典 3-1/UVa1585 3-2/UVa1586 3-3/UVa1225
书上具体所有题目:http://pan.baidu.com/s/1hssH0KO(我也是在网上找到的pdf,但不记得是从哪里搜刮到的了,就重新上传了一遍) PS:第一次写博客分享我的代码,不知道我对c ...
- 算法竞赛入门经典训练指南——UVA 11300 preading the Wealth
A Communist regime is trying to redistribute wealth in a village. They have have decided to sit ever ...
- 算法竞赛入门经典+挑战编程+USACO
下面给出的题目共计560道,去掉重复的也有近500题,作为ACMer Training Step1,用1年到1年半年时间完成.打牢基础,厚积薄发. 一.UVaOJ http://uva.onlinej ...
- 算法竞赛入门经典 LA 4329(树状数组)
题意: 一排有着不同能力值的人比赛,规定裁判的序号只能在两人之间,而且技能值也只能在两人之间 问题: <算法竞赛入门经典-训练指南>的分析: 上代码: #include<iostre ...
随机推荐
- mybatis resultMap 子元素
resultMap constructor - 类在实例化时,用来注入结果到构造方法中 idArg - ID 参数;标记结果作为 ID 可以帮助提高整体效能 arg - 注入到构造方法的一个普通结果 ...
- Python学习笔记——以函数为参数的内置函数
1.用法 一个参数 def ds(x): return 2 * x + 1 print(ds(5)) 11 g = lambda x : 2 * x + 1 print(g(5)) 11 两个参数 d ...
- 【机器学习】【计算机视觉】非常全面的图像数据集《Actions》
目录(?)[+] 1.搜狗实验室数据集: http://www.sogou.com/labs/dl/p.html 互联网图片库来自sogou图片搜索所索引的部分数据.其中收集了包括人物.动物.建筑 ...
- Linux正则表达式扩展部分第一波深度实践详解
扩展的正则表达式(Extended Regular Expressions): 使用的命令:grep -E 以及 egrep [了解即可] 1)+ 表示重复”一个或一个以上“ 前面的字符(*是0或多 ...
- eval 命令
eval命令用于重新运算求出参数的内容. eval可读取一连串的参数,然后再依参数本身的特性来执行. 语法: eval [参数]示例:eval echo 123
- LESSON 6- Quantization
如果输入本身就是离散的(比如text, computer files…), 对于这种discrete sources不需要量化可以直接进行离散信源编码. 如果输入是waveform(比如声音),取样为 ...
- 灾备系统 RTO与RPO
出处: https://blog.51cto.com/se7en/1085442 http://www.iso27001.org.cn/fuwu/it/iso22301/show_511.html h ...
- ARST 第五周打卡
Algorithm : 做一个 leetcode 的算法题 /////////////////////////////////////////////////////////////////// // ...
- Python学习笔记:运算符
逻辑运算符: + 加 - 减 * 乘 / 除 % 取模-返回除法的余数 ** 幂-返回x的y次方 // 整除 比较运算符: == 等于-比较对象是否相等 != ...
- HTML DOM focus() 方法
目录 HTML DOM focus() 方法 实例 定义和使用 浏览器支持 语法 参数 技术描述 更多实例 实例 实例 HTML DOM focus() 方法 实例 为 <a> 元素设置焦 ...