原题链接

题目描述

在一个地区有 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. docker search 报错

    docker 出现 Error response from daemon vim /etc/containers/registries.conf [registries.search]registri ...

  2. maven——将jar安装到本地仓库

    环境变量MAVEN_HOME配置正确后,cmd窗口执行此命令: mvn install:install-file -Dfile=C:\hehe.jar  -DgroupId=com.rockontro ...

  3. 在vue中让某个组件重新渲染的笨方法

    在vue中,推崇的是数据驱动也就是数据更新进而使组件得以重新渲染:在某些情况下,我们想要在数据不改变的情况下,重新渲染组件:我遇到的一个情况是:同一个页面,两个tab页分别为tab1和tab2,公用了 ...

  4. Ubuntu更换科大源

    更换科大源 方案一:在命令行输入 sudo gedit /etc/apt/sources.list ,打开系统自带源文件. 将文件内源删除,更换为以下科大源: deb http://mirrors.a ...

  5. ABC044 Digit Sum

    题目链接 我的思路略复杂,这里介绍一个比较简洁的做法. 对于 $b \le \sqrt{N}$,暴力枚举 $b$.对于 $b > \sqrt{N}$, 注意到在 $b$ 进制下 $N$ 至多有 ...

  6. Codeforces 1178F2. Long Colorful Strip

    传送门 首先涂区间,那么区间最多有 $2n$ 个相邻位置不同的情况,并且连续相同的颜色可以合并起来 那么这样操作完以后,区间长度最多为 $2n$ 发现涂完一段区间以后其他的操作都不能出现一边在区间内而 ...

  7. springboot指定redis库编号配置实现

    yml配置 spring: redis: database: #shiro host: 127.0.0.1 port: timeout: password: null redis-cache: dat ...

  8. Cannot call sendRedirect() after the response has been committed的解决办法

    做一个Login Demo的时候,写了如下代码: protected void doPost(HttpServletRequest request, HttpServletResponse respo ...

  9. gflags 编译动态库

    gflags 编译动态库 这里涉及到gflags的安装,原来使用 sudo apt-get install libgflags-dev 但是后面有人在环境中下载安装了libgflags的安装包,解压后 ...

  10. SpringBoot整合Mybatis关于分页查询的方法

    最近公司在用到SpringBoot整合Mybatis时当web端页面数据增多时需要使用分页查询以方便来展示数据.本人对分页查询进行了一些步骤的总结,希望能够帮助到有需要的博友.如有更好的方式,也希望评 ...