原题传送门


题意

给定一个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实现 蓝桥杯 算法提高 字符串压缩

    试题 算法提高 字符串压缩 资源限制 时间限制:1.0s 内存限制:256.0MB 问题描述 编写一个程序,输入一个字符串,然后采用如下的规则对该字符串当中的每一个字符进行压缩: (1) 如果该字符是 ...

  2. java实现串的反转

    串的反转 反转串 我们把"cba"称为"abc"的反转串. 求一个串的反转串的方法很多.下面就是其中的一种方法,代码十分简洁(甚至有些神秘),请聪明的你通过给出 ...

  3. java实现填写算式

    ** 填写算式** 看这个算式: ☆☆☆ + ☆☆☆ = ☆☆☆ 如果每个五角星代表 1 ~ 9 的不同的数字. 这个算式有多少种可能的正确填写方法? 173 + 286 = 459 295 + 17 ...

  4. iOS-Swift版本自定义CStextView的实现

    CSTextView继承自UITextView,并为其增加了placeHolder属性,支持代码和SB方式创建:demo实现了CSTextView的自动排版 效果图 CSTextView地址: htt ...

  5. STM32串口打印的那些知识

    常规打印方法 在STM32的应用中,我们常常对printf进行重定向的方式来把打印信息printf到我们的串口助手.在MDK环境中,我们常常使用MicroLIB+fputc的方式实现串口打印功能,即: ...

  6. CentOS7.6操作系统安装实例以及Linux版本、哲学思想介绍

    Linux起源1991年的10月5日,Torvalds在comp.os.minix新闻组上发布消息,正式向外宣布他自行编写的完全自由免费的内核诞生(Freeminix-like kernel sour ...

  7. Vue好书推荐

    1.Vue.js实战 从基础知识到ui组件封装和剖析,层层推进,最后两个案例实战.适合零基础入门,学完可就业.(推荐看这本) 交流地址(pdf原件):链接(点击跳转):提取码:7IsG 2.vue.j ...

  8. 如何解决flutter中gradle慢的问题

    初学flutter的时候,flutter run运行到有gradle的时候就停住不动了,研究后解决方法如下: 打开项目目录 中的 ...\myapp\android\gradle\wrapper\gr ...

  9. CMDB 和自动化运维

    目录 传统运维和自动化运维的对比 CMDB CMDB 的几种实现方式 传统运维和自动化运维的对比 1.企业中,项目的发布流程 产品经理调研需求 -->三方开会讨论(开发,产品,运维,测试) -– ...

  10. thinkphp5集成GatewayWorker

    Workerman是一款纯PHP开发的开源高性能的PHP socket 服务器框架,而GatewayWorker则是基于Workerman开发的一个长连接框架,支持分布式部署,支持全局广播或者向任意客 ...