原题链接

题目描述

在一个地区有 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. 换句话表示是什么?

不要走最长的路

  1. 什么是最长的路?

树的直径

  1. 树的直径是什么?

一棵树上,最远的两个点,他们的距离.

  1. 添加路径有什么效果?

使得两个点的最短距离变成\(1\).

  1. 当只能增加一条新的路径的时候,我们怎么最大化利润?

找到树的直径的两个端点,在他们中间添加一条新路径.

样例分析

这是我们样例1的模型.

让我们来求一下这棵树的树的直径

假如说我们将这条直径的两个端点连接的话,我们最多可以优惠多少路径长度呢?

性质是什么,就是从一个特殊例子,变化成为一个通解公式


性质总结

因此我们通过上面的每一步,得到了如下的这些重要性质.

  1. 刚开始我们一共要走的长度是:

\[路径总长度=2*(n-1)\\\\
n是这棵树上的节点个数
\]

因为对于每一个而言,我们必须要走两次. (你可以认为就像是DFS搜索一样)

第一次访问这个点,也就是进入这个点.

第二次访问这个点,也就是离开这个点.


  1. 假如说我们之前的树,它的树的直径长度是\(L\),那么经过我们第一轮路径增加过后.

\[路径总长度-L+1 \\\\
也就是2*(n-1)-L+1
\]

因为我们不必再走一遍树的直径了,所以我们减少了\(L\)的长度.

但是我们增加了一条边,所以我们增加了\(1\)的长度.

总而言之,言而总之,这就是我们对于增加一条边的性质总结.


重点思考

这道题目,不仅仅要让我们增加一条边,还有增加第二条边的可能.

假如说我们没有第一条边的建立,那么现在我们增加第二条边,其实所有步骤都是和上面建立第一条边是一样的.

  1. 第一条边建立后的影响

我们知道,树之所以是树,是因为它不会出现环.

但是现在一条边的建立,环它出现了.是他,是他,就是他,我们的小英雄一组环

因为出现了环,所以我们现在不能保证一个点,那就是

第二条边构造的B环会不会和第一条边构造的A环,有重叠部分.

  1. 假如说没有重叠部分

如果说没有重叠,那么第一条边和第二条边各自为政,井水不犯河水,我们可以看作是两次第一条边.

只需要把第一次步骤,重复两遍即可.

  1. 如果有重叠部分

我们现在要明确一点,为什么我们添加边,可以使得路径缩小?

因为对于树的直径上的所有点,我们只需要进入一次,并不需要再离开一次了.

  1. 但是重叠部分会导致什么呢?

对于一个节点而言,它是重叠部分上的点.

第一次,它被减少掉了一条边.

第二次,它再次被减少了一条边.

请问它还会被访问吗?

答案是不可能!因为我们一个节点,最多访问两次,而你减少了两次.

所以此时,我们的这些重叠部分上的点,从只需要访问一次,变成了需要访问两次.

因为我们必须去访问这些点,而访问了一次,又必须再离开一次,于是就是访问两次


算法流程
  1. 在最初的树上,求出树的直径\(L1\),然后将这条路径上的所有边权统统取反.

    \[1变成-1
    \]

  2. 我们再求一次树的直径\(L2\).

  3. 答案就是

    \[2 \times (n-1)-(L1-1)-(L2-1) \\\\
    = 2 \times (n-1)-L1+1-L2+1
    \]

假如说\(L2\)和\(L1\)有重叠部分.

那么当我们

\[-L1+1
\]

的时候,我们就会发现,重叠的部分变成了只需要经过一次.

然后

\[-L2+1
\]

相当于把重叠部分相加回来了.

此时变成了经过了两次.

假如说没有重叠部分,那么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] 算法竞赛竞赛经典 巡逻的更多相关文章

  1. (Step1-500题)UVaOJ+算法竞赛入门经典+挑战编程+USACO

    http://www.cnblogs.com/sxiszero/p/3618737.html 下面给出的题目共计560道,去掉重复的也有近500题,作为ACMer Training Step1,用1年 ...

  2. [刷题]算法竞赛入门经典 3-12/UVa11809

    书上具体所有题目:http://pan.baidu.com/s/1hssH0KO 题目:算法竞赛入门经典 3-4/UVa11809:Floating-Point Numbers 代码: //UVa11 ...

  3. [刷题]算法竞赛入门经典 3-10/UVa1587 3-11/UVa1588

    书上具体所有题目:http://pan.baidu.com/s/1hssH0KO 题目:算法竞赛入门经典 3-10/UVa1587:Box 代码: //UVa1587 - Box #include&l ...

  4. [刷题]算法竞赛入门经典 3-7/UVa1368 3-8/UVa202 3-9/UVa10340

    书上具体所有题目:http://pan.baidu.com/s/1hssH0KO 都是<算法竞赛入门经典(第二版)>的题目,标题上没写(第二版) 题目:算法竞赛入门经典 3-7/UVa13 ...

  5. [刷题]算法竞赛入门经典 3-4/UVa455 3-5/UVa227 3-6/UVa232

    书上具体所有题目:http://pan.baidu.com/s/1hssH0KO 题目:算法竞赛入门经典 3-4/UVa455:Periodic Strings 代码: //UVa455 #inclu ...

  6. [刷题]算法竞赛入门经典 3-1/UVa1585 3-2/UVa1586 3-3/UVa1225

    书上具体所有题目:http://pan.baidu.com/s/1hssH0KO(我也是在网上找到的pdf,但不记得是从哪里搜刮到的了,就重新上传了一遍) PS:第一次写博客分享我的代码,不知道我对c ...

  7. 算法竞赛入门经典训练指南——UVA 11300 preading the Wealth

    A Communist regime is trying to redistribute wealth in a village. They have have decided to sit ever ...

  8. 算法竞赛入门经典+挑战编程+USACO

    下面给出的题目共计560道,去掉重复的也有近500题,作为ACMer Training Step1,用1年到1年半年时间完成.打牢基础,厚积薄发. 一.UVaOJ http://uva.onlinej ...

  9. 算法竞赛入门经典 LA 4329(树状数组)

    题意: 一排有着不同能力值的人比赛,规定裁判的序号只能在两人之间,而且技能值也只能在两人之间 问题: <算法竞赛入门经典-训练指南>的分析: 上代码: #include<iostre ...

随机推荐

  1. mybatis resultMap 子元素

    resultMap constructor - 类在实例化时,用来注入结果到构造方法中 idArg - ID 参数;标记结果作为 ID 可以帮助提高整体效能 arg - 注入到构造方法的一个普通结果 ...

  2. Python学习笔记——以函数为参数的内置函数

    1.用法 一个参数 def ds(x): return 2 * x + 1 print(ds(5)) 11 g = lambda x : 2 * x + 1 print(g(5)) 11 两个参数 d ...

  3. 【机器学习】【计算机视觉】非常全面的图像数据集《Actions》

    目录(?)[+]   1.搜狗实验室数据集: http://www.sogou.com/labs/dl/p.html 互联网图片库来自sogou图片搜索所索引的部分数据.其中收集了包括人物.动物.建筑 ...

  4. Linux正则表达式扩展部分第一波深度实践详解

    扩展的正则表达式(Extended Regular  Expressions): 使用的命令:grep -E 以及 egrep [了解即可] 1)+ 表示重复”一个或一个以上“ 前面的字符(*是0或多 ...

  5. eval 命令

    eval命令用于重新运算求出参数的内容. eval可读取一连串的参数,然后再依参数本身的特性来执行. 语法: eval [参数]示例:eval echo 123

  6. LESSON 6- Quantization

    如果输入本身就是离散的(比如text, computer files…), 对于这种discrete sources不需要量化可以直接进行离散信源编码. 如果输入是waveform(比如声音),取样为 ...

  7. 灾备系统 RTO与RPO

    出处: https://blog.51cto.com/se7en/1085442 http://www.iso27001.org.cn/fuwu/it/iso22301/show_511.html h ...

  8. ARST 第五周打卡

    Algorithm : 做一个 leetcode 的算法题 /////////////////////////////////////////////////////////////////// // ...

  9. Python学习笔记:运算符

    逻辑运算符: +   加 -    减 *    乘 /    除 %  取模-返回除法的余数 **  幂-返回x的y次方 //  整除 比较运算符: ==      等于-比较对象是否相等 !=  ...

  10. HTML DOM focus() 方法

    目录 HTML DOM focus() 方法 实例 定义和使用 浏览器支持 语法 参数 技术描述 更多实例 实例 实例 HTML DOM focus() 方法 实例 为 <a> 元素设置焦 ...