BZOJ3242 快餐店
题意
给定一个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 快餐店的更多相关文章
- 【BZOJ3242】【NOI2013】快餐店(动态规划)
[BZOJ3242][NOI2013]快餐店(动态规划) 题面 BZOJ 题解 假设我们要做的是一棵树,那么答案显然是树的直径的一半. 证明? 假设树的直径是\(2d\),那么此时最远点的距离是\(d ...
- 【BZOJ3242】【UOJ#126】【NOI2013】快餐店
NOI都是这种难度的题怎么玩嘛QAQ 原题: 小T打算在城市C开设一家外送快餐店.送餐到某一个地点的时间与外卖店到该地点之间最短路径长度是成正比的,小T希望快餐店的地址选在离最远的顾客距离最近的地方. ...
- BZOJ3242 [Noi2013]快餐店 【环套树 + 单调队列dp】
题目链接 BZOJ3242 题解 题意很清楚,找一点使得最远点最近 如果是一棵树,就是直径中点 现在套上了一个环,我们把环单独拿出来 先求出环上每个点外向树直径更新答案,并同时求出环上每个点外向的最远 ...
- BZOJ3242/UOJ126 [Noi2013]快餐店
本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...
- bzoj3242 [Noi2013]快餐店
Description 小T打算在城市C开设一家外送快餐店.送餐到某一个地点的时间与外卖店到该地点之间最短路径长度是成正比的,小T希望快餐店的地址选在离最远的顾客距离最近的地方. 快餐店的顾客分布在城 ...
- 3242: [Noi2013]快餐店 - BZOJ
Description 小T打算在城市C开设一家外送快餐店.送餐到某一个地点的时间与外卖店到该地点之间最短路径长度是成正比的,小T希望快餐店的地址选在离最远的顾客距离最近的地方. 快餐店的顾客分布在城 ...
- 快餐店运行模拟C++程序源码代写
某快餐店供应若干种快餐和饮料(5种以上),早晨6:00开始营业,晚上11:00打烊.前一天已经安排了若干工人上班,快餐店的用餐位是固定的,每种食物的成本和销售价格是确定的,每种食物的总量是确定的,储存 ...
- 从医生看病和快餐店点餐理解Node.js的事件驱动
第一个例子是关于医生看病. 在美国去看医生,需要填写大量表格,比如保险.个人信息之类,传统的基于线程的系统(thread-based system),接待员叫到你,你需要在前台填写完成这些表格,你站着 ...
- bzoj 3242: [Noi2013]快餐店 章鱼图
3242: [Noi2013]快餐店 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 266 Solved: 140[Submit][Status] ...
随机推荐
- Java实现 LeetCode 224 基本计算器
224. 基本计算器 实现一个基本的计算器来计算一个简单的字符串表达式的值. 字符串表达式可以包含左括号 ( ,右括号 ),加号 + ,减号 -,非负整数和空格 . 示例 1: 输入: "1 ...
- Java实现 蓝桥杯 一步之遥
一步之遥 从昏迷中醒来,小明发现自己被关在X星球的废矿车里. 矿车停在平直的废弃的轨道上. 他的面前是两个按钮,分别写着"F"和"B". 小明突然记起来,这两个 ...
- PAT 科学计数法
科学计数法是科学家用来表示很大或很小的数字的一种方便的方法,其满足正则表达式 [+-][1-9].[0-9]+E[+-][0-9]+,即数字的整数部分只有 1 位,小数部分至少有 1 位,该数字及其指 ...
- 使用macaca抓页面元素,执行命令后报安装失败处理Error: Command failed: ……pm install -r "/data/local/tmp/com.macaca.android.testing"
最近换了小米手机做自动化测试,执行命令的时候报安装失败错误,错误如下 解决:设置小米允许USB安装就好了 pm install -r "/data/local/tmp/com.macaca. ...
- 官宣!ASF官方正式宣布Apache Hudi成为顶级项目
马萨诸塞州韦克菲尔德(Wakefield,MA)- 2020年6月 - Apache软件基金会(ASF).350多个开源项目和全职开发人员.管理人员和孵化器宣布:Apache Hudi正式成为Apac ...
- 容器技术之Docker私有镜像仓库docker-distribution
在前边的博客中我们说到docker的架构由docker客户端.服务端以及仓库组成:docker仓库就是用来存放镜像的地方:其实docker registry我们理解为存放docker镜像仓库的仓库比较 ...
- 00-04.kaliLinux-手动配置IP地址
在KaliLinux中手动配置网卡 用vim打开网卡的配置文件,配置各个网卡信息 root@kali:~# cd /etc/network root@kali:/etc/network# ------ ...
- cubic-bezier() 函数
2020-03-13 cubic-bezier() 函数 ubic-bezier() 函数定义了一个贝塞尔曲线(Cubic Bezier). 贝塞尔曲线曲线由四个点 P0,P1,P2 和 P3 定义. ...
- 面试必问:分布式锁实现之zk(Zookeeper)
点赞再看,养成习惯,微信搜索[三太子敖丙]关注这个互联网苟且偷生的工具人. 本文 GitHub https://github.com/JavaFamily 已收录,有一线大厂面试完整考点.资料以及我的 ...
- 使用本地shadow socks代理
1,第一种方式 import urllib2 import socks from sockshandler import SocksiPyHandler opener = urllib2.build_ ...