原题传送门


题意

给定一个n条边n个点的连通图,求该图的某一点在该图距离最远的点距离它的距离的最小值。


题解

显然,答案是\(\frac {原图直径}{2}\)。

本体的图有 \(n\) 个点 \(n\) 条边,很显然是基环树。

那么拆掉任意一条环上的边,该图就会变为一颗普通树。

随意选择一条环上的边断开,设一端为 \(s\),一端为 \(t\), 长度为 \(len\)。

分类讨论一下该图的直径经过环和断边的情况:

1、直径经过断开的边;

2、直径不经过断开的边,经过环;

3、直径不经过环。

显然,若直径经过断开的边,就需要得出环上每个点的字数距离 \(s\) 最远点距离 \(s\) 的值,此值很显然可以在环上跑一边 \(DP\) 求出;

若直径不经过断开的边,则需要得出环上某两个点的子树的最远点之间的距离的最大值,此值仍然可以在环上跑一边 \(DP\) 求出。

故我们可以从 \(s\) 点开始,\(O(n)\) 从两个方向扫两遍环,在扫环的过程中,求出直径不经过环的情况的答案,同时维护两个 \(DP\) 值:

1、经过的环上的点的子树中,距离 \(s\) 最远的点距离 \(s\) 的值,定义该值为 \(u_1\)(正向)和 \(u_2\)(反向);

2、在经过的环上的点中,某两个距离最远的子树的最远点之间的距离,定义该值为 \(v_1\)(正向)和 \(v_2\)(反向);

扫描结束后,再遍历一遍环上的点更新答案值。

\(DP\) 方程:

\(ans = min(ans, max (max (v_1[i], v_2[i + 1]), u_1[i] + u_2[i + 1] + len))\)

注意更新结束后,还需要与直径不经过环的情况求一下最值。


代码:

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e5 + 5;
int n, sum, mx, cirsum, ans, ans1, tim, lstlen, f[N], u1[N], u2[N], v1[N], v2[N], fa[N], fal[N], tims[N], oncir[N], cirnum[N], cirlen[N];
vector <pair <int, int> > v[N];
void make_cir (int s, int t) {
int now = s;
while (now != t) {
oncir[now] = 1;
cirnum[++ cirsum] = now;
cirlen[cirsum] = fal[now];
now = fa[now];
}
return ;
}
void dfs (int x) {
tims[x] = ++ tim;
for (int i = 0; i < v[x].size (); i ++) {
int y = v[x][i].first;
if (tims[y] && tims[y] > tims[x]) {
make_cir (y, x);
oncir[x] = 1;
cirnum[++ cirsum] = x;
cirlen[cirsum] = v[x][i].second;
} else if (!tims[y]) {
fa[y] = x;
fal[y] = v[x][i].second;
dfs (y);
}
}
return ;
}
void dfs2 (int x, int lst) {
for (int i = 0; i < v[x].size(); i ++) {
int y = v[x][i].first, w = v[x][i].second;
if (y == lst || oncir[y])
continue ;
dfs2 (y, x);
ans = max (ans, f[x] + f[y] + w);
f[x] = max (f[x], f[y] + w);
}
return ;
}
signed main () {
scanf ("%lld", &n);
for (int i = 1; i <= n; i ++) {
int uu, vv, ww;
scanf ("%lld%lld%lld", &uu, &vv, &ww);
v[uu].push_back (make_pair (vv, ww));
v[vv].push_back (make_pair (uu, ww));
}
dfs (1);
for (int i = 1; i <= cirsum; i ++)
dfs2 (cirnum[i], 0);
for (int i = 1; i <= cirsum; i ++) {
sum += cirlen[i - 1];
u1[i] = max (u1[i - 1], f[cirnum[i]] + sum);
v1[i] = max (v1[i - 1], f[cirnum[i]] + mx + sum);
mx = max (mx, f[cirnum[i]] - sum);
}
lstlen = cirlen[cirsum];
cirlen[cirsum] = 0;
sum = 0;
mx = 0;
for (int i = cirsum; i >= 1; i --) {
sum += cirlen[i];
u2[i] = max (u2[i + 1], f[cirnum[i]] + sum);
v2[i] = max (v2[i + 1], f[cirnum[i]] + mx + sum);
mx = max (mx, f[cirnum[i]] - sum);
}
ans1 = v1[cirsum];
for (int i = 1; i < cirsum; i ++)
ans1 = min (ans1, max (max (v1[i], v2[i + 1]), u1[i] + u2[i + 1] + lstlen));
ans = max (ans, ans1);
printf ("%.1lf\n", (double)(ans / 2));
return 0;
}

本博客思路参考自 https://blog.csdn.net/zlttttt/article/details/73149529

BZOJ3242 快餐店的更多相关文章

  1. 【BZOJ3242】【NOI2013】快餐店(动态规划)

    [BZOJ3242][NOI2013]快餐店(动态规划) 题面 BZOJ 题解 假设我们要做的是一棵树,那么答案显然是树的直径的一半. 证明? 假设树的直径是\(2d\),那么此时最远点的距离是\(d ...

  2. 【BZOJ3242】【UOJ#126】【NOI2013】快餐店

    NOI都是这种难度的题怎么玩嘛QAQ 原题: 小T打算在城市C开设一家外送快餐店.送餐到某一个地点的时间与外卖店到该地点之间最短路径长度是成正比的,小T希望快餐店的地址选在离最远的顾客距离最近的地方. ...

  3. BZOJ3242 [Noi2013]快餐店 【环套树 + 单调队列dp】

    题目链接 BZOJ3242 题解 题意很清楚,找一点使得最远点最近 如果是一棵树,就是直径中点 现在套上了一个环,我们把环单独拿出来 先求出环上每个点外向树直径更新答案,并同时求出环上每个点外向的最远 ...

  4. BZOJ3242/UOJ126 [Noi2013]快餐店

    本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...

  5. bzoj3242 [Noi2013]快餐店

    Description 小T打算在城市C开设一家外送快餐店.送餐到某一个地点的时间与外卖店到该地点之间最短路径长度是成正比的,小T希望快餐店的地址选在离最远的顾客距离最近的地方. 快餐店的顾客分布在城 ...

  6. 3242: [Noi2013]快餐店 - BZOJ

    Description 小T打算在城市C开设一家外送快餐店.送餐到某一个地点的时间与外卖店到该地点之间最短路径长度是成正比的,小T希望快餐店的地址选在离最远的顾客距离最近的地方. 快餐店的顾客分布在城 ...

  7. 快餐店运行模拟C++程序源码代写

    某快餐店供应若干种快餐和饮料(5种以上),早晨6:00开始营业,晚上11:00打烊.前一天已经安排了若干工人上班,快餐店的用餐位是固定的,每种食物的成本和销售价格是确定的,每种食物的总量是确定的,储存 ...

  8. 从医生看病和快餐店点餐理解Node.js的事件驱动

    第一个例子是关于医生看病. 在美国去看医生,需要填写大量表格,比如保险.个人信息之类,传统的基于线程的系统(thread-based system),接待员叫到你,你需要在前台填写完成这些表格,你站着 ...

  9. bzoj 3242: [Noi2013]快餐店 章鱼图

    3242: [Noi2013]快餐店 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 266  Solved: 140[Submit][Status] ...

随机推荐

  1. Java中StringBuffer和StringBuilder的区别

    区别1线程安全: StringBuffer是线程安全的,StringBuilder是线程是不安全的.因为StringBuffer的所有公开方法都用synchronized 来修饰,StringBuil ...

  2. Java实现 LeetCode 27 移除元素

    27. 移除元素 给定一个数组 nums 和一个值 val,你需要原地移除所有数值等于 val 的元素,返回移除后数组的新长度. 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额 ...

  3. java实现最大五个数

    ** 最大5个数** [12,127,85,66,27,34,15,344,156,344,29,47,....] 这是某设备测量到的工程数据. 因工程要求,需要找出最大的5个值. 一般的想法是对它排 ...

  4. Linux fdisk手动分区

    查询系统中可以被识别的硬盘:fdisk -l 可以看到,我的服务器只有一块硬盘,容量是53.7GB,有1个分区,文件系统类型是Linux,Id 是83(82是Linux swap分区,相当于Windo ...

  5. svg 贝塞尔曲线图解(记录)

    path路径绘制中,绘制贝塞尔曲线的命令包括: Q 二次贝赛尔曲线 x1,y1 x,y T 平滑二次贝塞尔曲线 x,y C 曲线(curveto) x1,y1 x2,y2 x,y S 平滑曲线 x2, ...

  6. python numpy 库

    引用文章:https://blog.csdn.net/xjl271314/article/details/80409034

  7. SaaS权限设计总结

    2年前转到SaaS部门之后期间断断续续做着权限相关的业务,这篇文章主要回顾下过往的设计以及其原因和利弊. 不过因为是线上业务,会省略掉很多细节以及账号体系和权益相关得部分,只讨论权限相关. 本文也不会 ...

  8. Python内存管理机制-《源码解析》

    Python内存管理机制 Python 内存管理分层架构 /* An object allocator for Python. Here is an introduction to the layer ...

  9. 自己动手实现深度学习框架-7 RNN层--GRU, LSTM

    目标         这个阶段会给cute-dl添加循环层,使之能够支持RNN--循环神经网络. 具体目标包括: 添加激活函数sigmoid, tanh. 添加GRU(Gate Recurrent U ...

  10. Spring WebFlux 学习笔记 - (一) 前传:学习Java 8 Stream Api (2) - Stream的中间操作

    Stream API Java8中有两大最为重要的改变:第一个是 Lambda 表达式:另外一个则是 Stream API(java.util.stream.*). Stream 是 Java8 中处 ...