树的直径【p3629】[APIO2010]巡逻
Description
在一个地区中有 n 个村庄,编号为 1, 2, ..., n。有 n – 1 条道路连接着这些村 庄,每条道路刚好连接两个村庄,从任何一个村庄,都可以通过这些道路到达其 他任一个村庄。每条道路的长度均为 1 个单位。 为保证该地区的安全,巡警车每天要到所有的道路上巡逻。警察局设在编号 为 1 的村庄里,每天巡警车总是从警察局出发,最终又回到警察局。 下图表示一个有 8 个村庄的地区,其中村庄用圆表示(其中村庄 1 用黑色的 圆表示),道路是连接这些圆的线段。为了遍历所有的道路,巡警车需要走的距 离为 14 个单位,每条道路都需要经过两次。
为了减少总的巡逻距离,该地区准备在这些村庄之间建立 K 条新的道路, 每条新道路可以连接任意两个村庄。两条新道路可以在同一个村庄会合或结束 (见下面的图例(c))。 一条新道路甚至可以是一个环,即,其两端连接到同一 个村庄。 由于资金有限,K 只能是 1 或 2。同时,为了不浪费资金,每天巡警车必须 经过新建的道路正好一次。 下图给出了一些建立新道路的例子:
在(a)中,新建了一条道路,总的距离是 11。在(b)中,新建了两条道路,总 的巡逻距离是 10。在(c)中,新建了两条道路,但由于巡警车要经过每条新道路 正好一次,总的距离变为了 15。 试编写一个程序,读取村庄间道路的信息和需要新建的道路数,计算出最佳 的新建道路的方案使得总的巡逻距离最小,并输出这个最小的巡逻距离。
Input
第一行包含两个整数 n, K(1 ≤ K ≤ 2)。接下来 n – 1 行,每行两个整数 a, b, 表示村庄 a 与 b 之间有一条道路(1 ≤ a, b ≤ n)。
Output
输出一个整数,表示新建了 K 条道路后能达到的最小巡逻距离。
很明显,新建的边要在树上最长的链(树的直径)上建.构成一个最大的环.这样能使我们走过这些在直径上的边对答案的影响最小.
如果建两条边,同理,第二条边要建在次长链上,
问题难在如何求出次长链.
我们只需要将直径上的边的边权全部标成\(-1\)就好了.
这样就对这些边对答案的贡献就可以抵消了,就达到了不选的效果.
这里用\(dfs\)求了树的直径,又用树形\(Dp\)求了新的直径.
应该不是很难理解.
代码
#include<cstdio>
#include<cctype>
#include<iostream>
#define N 100008
#define R register
using namespace std;
inline void in(int &x)
{
int f=1;x=0;char s=getchar();
while(!isdigit(s)){if(s=='-')f=-1;s=getchar();}
while(isdigit(s)){x=x*10+s-'0';s=getchar();}
x*=f;
}
int n,k,head[N],tot=1,pos,dis[N]={-1},root,mx,pre[N],mxx;
struct cod{int u,v,w;}edge[N<<2];
int dist[N];
bool vis[N];
inline void add(int x,int y)
{
edge[++tot].u=head[x];
edge[tot].v=y;
edge[tot].w=1;
head[x]=tot;
}
void dfs(int u,int fa)
{
dis[u]=dis[fa]+1;
for(R int i=head[u];i;i=edge[i].u)
{
if(edge[i].v==fa)continue;
dfs(edge[i].v,u);
pre[edge[i].v]=i;
}
}
void dp(int x)
{
vis[x]=true;
for(R int i=head[x];i;i=edge[i].u)
{
if(vis[edge[i].v])continue;
dp(edge[i].v);
mxx=max(mxx,dist[x]+dist[edge[i].v]+edge[i].w);
dist[x]=max(dist[x],dist[edge[i].v]+edge[i].w);
}
}
int main()
{
in(n);in(k);
for(R int i=1,x,y;i<n;i++)
in(x),in(y),add(x,y),add(y,x);
dfs(1,0);
for(R int i=1;i<=n;i++)root=dis[i]>dis[root]?i:root;
for(R int i=1;i<=n;i++)dis[i]=pre[i]=0;
dfs(root,0);
for(R int i=1;i<=n;i++)
if(dis[i]>mx)
{
mx=dis[i];
pos=i;
}
if(k==1)
{
printf("%d",2*(n-1)+1-mx);
return 0;
}
for(R int i=pre[pos];i;i=pre[edge[i^1].v])
edge[i].w=edge[i^1].w=-1;
dp(root);
printf("%d",2*(n-1)+2-mx-mxx);
}
树的直径【p3629】[APIO2010]巡逻的更多相关文章
- 洛谷 P3629 [APIO2010]巡逻 解题报告
P3629 [APIO2010]巡逻 题目描述 在一个地区中有 n 个村庄,编号为 1, 2, ..., n.有 n – 1 条道路连接着这些村 庄,每条道路刚好连接两个村庄,从任何一个村庄,都可以通 ...
- 树的直径初探+Luogu P3629 [APIO2010]巡逻【树的直径】By cellur925
题目传送门 我们先来介绍一个概念:树的直径. 树的直径:树中最远的两个节点间的距离.(树的最长链)树的直径有两种方法,都是$O(N)$. 第一种:两遍bfs/dfs(这里写的是两遍bfs) 从任意一个 ...
- 洛谷P3629 [APIO2010]巡逻(树的直径)
如果考虑不算上新修的道路,那么答案显然为\(2*(n-1)\). 考虑\(k=1\)的情况,会发现如果我们新修建一个道路,那么就会有一段路程少走一遍.这时选择连接树的直径的两个端点显然是最优的. 难就 ...
- [洛谷P3629] [APIO2010]巡逻
洛谷题目链接:[APIO2010]巡逻 题目描述 在一个地区中有 n 个村庄,编号为 1, 2, ..., n.有 n – 1 条道路连接着这些村 庄,每条道路刚好连接两个村庄,从任何一个村庄,都可以 ...
- P3629 [APIO2010]巡逻
题目描述 在一个地区中有 n 个村庄,编号为 1, 2, ..., n.有 n – 1 条道路连接着这些村 庄,每条道路刚好连接两个村庄,从任何一个村庄,都可以通过这些道路到达其 他任一个村庄.每条道 ...
- 洛谷 P3629 [APIO2010]巡逻
题目在这里 这是一个紫题,当然很难. 我们往简单的想,不建立新的道路时,从1号节点出发,把整棵树上的每条边遍历至少一次,再回到1号节点,会恰好经过每条边两次,路线总长度为$2(n-1)$,根据树的深度 ...
- 题解 BZOJ 1912 && luogu P3629 [APIO2010]巡逻 (树的直径)
本来抄了篇题解,后来觉得题解都太不友好(我太菜了),一气之下自己打...一打打到第二天QAQ 首先什么边也不加时,总路程就是2*(n-1) 考虑k=1的时候,答案显然是2*(n-1)-直径+1=2*n ...
- P3629 [APIO2010] 巡逻 (树的直径)
(这道题考察了求直径的两种方法......) 在原图中,每条边要经过两次,增加1条后,形成了一个环,那么环上的边只需要经过一次了(大量画图分析得),再增加一条又会形成一个环,如果这两个环有重叠,重叠部 ...
- 【题解】P3629 [APIO2010]巡逻
link 题意 有 \(n\) 个村庄,编号为 \(1, 2, ..., n\) .有 \(n – 1\) 条道路连接着这些村 庄,从任何一个村庄都可以到达其他任一个村庄.道路长度均为 1. 巡警车每 ...
- 树的直径,LCA复习笔记
前言 复习笔记第6篇. 求直径的两种方法 树形DP: dfs(y); ans=max( ans,d[x]+d[y]+w[i] ); d[x]=max( d[x],d[y]+w[i] ); int di ...
随机推荐
- USACO Section1.4 Mother's Milk 解题报告
milk3解题报告 —— icedream61 博客园(转载请注明出处)---------------------------------------------------------------- ...
- maven的一些使用配置!
1.国外库太慢,更换为国内镜像库在你的maven安装目录下找到conf目录下的setting.xml修改:<mirrors> <id>CN</id> <nam ...
- 自动化测试(三)如何用python写个双色球
写一个程序,输入N就产生N条双色球号码 红球 6 01-33 蓝球 1 01-16 产生的双色球号码不能重复,写到一个文件里面,每一行是一条 红球: 01 03 05 07 08 ...
- Python 高级 I/O 多路复用
Table of Contents 前言 select selectors 结语 参考链接 前言 第一次接触和 I/O 多路复用相关的概念是在书 CSAPP1 的并发编程章节,当时在了解了这个概念后只 ...
- ZOJ 3606 Lazy Salesgirl ( 线段树 + 思路 )
卖切糕的小女孩 http://www.cnblogs.com/wuyiqi/archive/2012/04/28/2474672.html #include <cstdio> #inclu ...
- [转]Android的网络与通信
本文转自:http://www.cnblogs.com/qingblog/archive/2012/06/15/2550735.html 第一部分 Android网络基础 Android平台浏览器 ...
- Nagios 监控系统架设全攻略
Nagios 全名为(Nagios Ain’t Goona Insist on Saintood),最初项目名字是 NetSaint.它是一款免费的开源 IT 基础设施监控系统,其功能强大,灵活性强, ...
- InnoDB 存储引擎的线程与内存池
InnoDB 存储引擎的线程与内存池 InnoDB体系结构如下: 后台线程: 1.后台线程的主要作用是负责刷新内存池中的数据,保证缓冲池中的内存缓存的是最近的数据: 2.另外,将以修改的数据文件刷 ...
- sql server 中使用 LIKE 语句 SqlParameter 使用
原本写的 select * from table where name like '%@searchStr%' 怎么执行都不对,想想 参数是不能加 引号的 于是改为select * from tab ...
- hdu 2579 Dating with girls(2) (bfs)
Dating with girls(2) Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Oth ...