原题链接

题目描述

在一个地区有 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. 关于Linux系统打开最大文件数量

    今天做压力测试 客户端数据提到2000人,在这个过程中,遇到了分配socket失败的问题提示 errno:24 Too many open files查找资料后发现是Linux系统配置了打开文件的最大 ...

  2. Etherscan

    转载声明:https://blog.csdn.net/shebao3333/article/details/79858250 (仅方便自己查看及原文章被删除) 什么是Etherscan? 简单来说是一 ...

  3. 【CSS】如何在一个页面中引入样式css

    CSS(Cascading Style Sheet)又叫层叠样式表.是我们学习前端必不可少的一门语言,学习它其实就是为了学会如何去更改页面标签的样式.目前使用最广的是css3,但同样的,他是从css2 ...

  4. 【Python】【demo实验28】【练习实例】【递归函数练习】

    原题: 有5个人坐在一起,问第五个人多少岁?他说比第4个人大2岁.问第4个人岁数,他说比第3个人大2岁.问第三个人,又说比第2人大两岁.问第2个人,说比第一个人大两岁.最后问第一个人,他说是10岁.请 ...

  5. mysql查询出数据更新到另一张表

    公司今天有个需求,大体意思就是把一个表的玩家游戏场数统计出来,然后赋值到另一张表的字段上,说白了就是两张表,但是查询出来的玩家账号和次数是多条,尝试很多种写法都没用,最后用了最笨的方式解决. -- - ...

  6. linux内核编程入门 hello world

    注意: Makefile 文件的命名注意M需要大写,否则会报错. 在Makefile文件中make命令前应为tab制表符. 下文转载至:https://blog.csdn.net/bingqing07 ...

  7. 数据结构-二叉搜索树Java实现

    1,Node.java 生成基础二叉树的结构 package com.cnblogs.mufasa.searchTree; /** * 节点配置父+左+右 */ public class Node{ ...

  8. spring-test跟junit结合单元测试获取ApplicationContext实例的方法

    步骤 1.继承AbstractJUnit4SpringContextTests 2.引入ApplicationContext   示例代码:(可以根据name或者类型获取bean) import or ...

  9. 汉明码(hamming code)

    hamming code用于磁盘RAID 2中, 关于汉明码的讲解可以看这篇博文,介绍的很详细.最重要是最后的结论: 汉明码属于分组奇偶校验,P4P2P1=000,说明接收方生成的校验位和收到的校验位 ...

  10. NSIS逻辑函数头文件介绍

    !include "LogicLib.nsh"使用 NSIS 的宏来提供各种逻辑基本语句,不需要预先添加函数. 基本语句 If|Unless..{ElseIf|ElseUnless ...