P2571 [SCOI2010]传送带——hyl天梦
P2571 [SCOI2010]传送带题解————天梦
如写的不好,请多见谅。
对于这道题,我首先想说,确实困惑了我好久,看网上的各种题解,却都不尽人意,思路早已明白,却不会操作。最后想想,还是觉得自己试着写一个吧。一种思路,与题解的思路不同,但理论上可行,但我当时似乎也不太相信那所谓的“理论”,毕竟自己错过许多次,即使这样仍要相信自己吗?想着,便已经翻到了我所需要的——与自己思路相同的题解。网址是https://blog.csdn.net/qq_42920122/article/details/88622782,什么思路呢?,在这之前,我建议大家,一定要相信自己,接下来让我们一起往下看。
题目
引入
现在请各位读者先抛开这个题,先想这样一个问题,如果在一个平面上,有一个点E和一条线段CD,一般的,如何求得点到线段得最短距离?
这个问题很简单,答案:垂线段最短。所以,如果我们在垂足两侧取点,所得到的答案肯定比垂线段大。如果有一个动点P,从端点C运动到端点D,设在平面直角坐标系中,x为PC的长度,y为PE的长度,那么这个函数是一定是一个形如谷底(山峰)的图像。我们都知道,有单调性时,可以用二分。极值怎么办?答案是三分。
如果不懂三分,请参考其它博客。推荐https://www.cnblogs.com/newpanderking/archive/2011/08/25/2153777.html 我用的三分并不规范。
思路
有一个小事情大家可以理解一下。在题中,最优解实际上满足在AB上取一点E,在CD上取一点F作为拐点,即AE+EF+FD,为什么?读者可以自己画一画,即使你取两个不在线段上的点,也会有两个在直线上的点可以比原先点更优。
好了,问题来了,两条直线怎么办?如果我们已经确定点E,那么,根据“引入”,我们就可以确定答案了,但是我们并不知道,怎么办?答案:三分AB就可以了。详细看代码。
代码
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<sstream>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<deque>
#define dd double
#define ll long long
#define N 10000100
using namespace std;
dd ans=N;
struct point{
dd x,y;//存点的坐标
};
point a,b,c,d;
int p,q,r;
const dd eps=1e-8;//精度,我比较习惯于开1e-8;
dd dis(point l,point r)
{
return sqrt((l.x-r.x)*(l.x-r.x)+(l.y-r.y)*(l.y-r.y));
}//求点l到点r的距离,勾股定理
dd f(point mid2,point midmid)
{
return dis(mid2,midmid)/r+dis(midmid,d)/q;
}//这个函数是对于AB上的点mid2和在CD上的点midmid,求一下从mid到midmid和midmid到点d的“时间”;
dd Three_CD(point mid2)//三分CD,mid2是已将选好的“E”
{
dd zanans=N;
point l,r; l.x=c.x; l.y=c.y; r.x=d.x; r.y=d.y;
while(dis(l,r)>eps)
{
point mid,midmid;
mid.x=(l.x+r.x)/2.0; mid.y=(l.y+r.y)/2.0;
midmid.x=(mid.x+r.x)/2.0; midmid.y=(mid.y+r.y)/2.0;
if(f(mid2,mid)<f(mid2,midmid))
{
zanans=min(ans,f(mid2,mid));
r=midmid;
}
else
{
zanans=min(ans,f(mid2,midmid));
l=mid;
}
}
return zanans;
}
int main()
{
cin>>a.x>>a.y>>b.x>>b.y>>c.x>>c.y>>d.x>>d.y>>p>>q>>r;
point l,r; l.x=a.x; l.y=a.y; r.x=b.x; r.y=b.y;
while(dis(l,r)>eps)//三分AB
{
point mid,midmid;
mid.x=(l.x+r.x)/2.0; mid.y=(l.y+r.y)/2.0;
midmid.x=(mid.x+r.x)/2.0; midmid.y=(mid.y+r.y)/2.0;
dd ans1=Three_CD(mid);
dd ans2=Three_CD(midmid);//ans1是以mid为E的最优解,ans2同理,看着两个值哪个最优。
//cout<<ans1<<" "<<ans2<<" ";
ans1=ans1+dis(a,mid)/p;
ans2=ans2+dis(a,midmid)/p;
//cout<<ans1<<" "<<ans2<<" ";
if(ans1<ans2)
{
ans=min(ans,ans1);
r=midmid;
}
else
{
ans=min(ans,ans2);
l=mid;
}//更新ans
//printf("%0.2lf\n",ans);
}
printf("%0.2lf",ans);
return 0;
}
你以为这就完了,不,没有!
坑点
请大家仔细想想,如若A、B两点重合,会怎么样?ans将会是N!C、D重合是一个道理。do-while可以很好地解决这个问题。
真正AC代码(无注释)
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<sstream>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<deque>
#define dd double
#define ll long long
#define N 10000100
using namespace std;
dd ans=N;
struct point{
dd x,y;
};
point a,b,c,d;
int p,q,r;
const dd eps=1e-8;
dd dis(point l,point r)
{
return sqrt((l.x-r.x)*(l.x-r.x)+(l.y-r.y)*(l.y-r.y));
}
dd f(point mid2,point midmid)
{
return dis(mid2,midmid)/r+dis(midmid,d)/q;
}
dd Three_CD(point mid2)
{
dd zanans=N;
point l,r; l.x=c.x; l.y=c.y; r.x=d.x; r.y=d.y;
do
{
point mid,midmid;
mid.x=(l.x+r.x)/2.0; mid.y=(l.y+r.y)/2.0;
midmid.x=(mid.x+r.x)/2.0; midmid.y=(mid.y+r.y)/2.0;
if(f(mid2,mid)<f(mid2,midmid))
{
zanans=min(ans,f(mid2,mid));
r=midmid;
}
else
{
zanans=min(ans,f(mid2,midmid));
l=mid;
}
}
while(dis(l,r)>eps);
return zanans;
}
int main()
{
cin>>a.x>>a.y>>b.x>>b.y>>c.x>>c.y>>d.x>>d.y>>p>>q>>r;
point l,r; l.x=a.x; l.y=a.y; r.x=b.x; r.y=b.y;
do
{
point mid,midmid;
mid.x=(l.x+r.x)/2.0; mid.y=(l.y+r.y)/2.0;
midmid.x=(mid.x+r.x)/2.0; midmid.y=(mid.y+r.y)/2.0;
dd ans1=Three_CD(mid);
dd ans2=Three_CD(midmid);
//cout<<ans1<<" "<<ans2<<" ";
ans1=ans1+dis(a,mid)/p;
ans2=ans2+dis(a,midmid)/p;
//cout<<ans1<<" "<<ans2<<" ";
if(ans1<ans2)
{
ans=min(ans,ans1);
r=midmid;
}
else
{
ans=min(ans,ans2);
l=mid;
}
//printf("%0.2lf\n",ans);
}while(dis(l,r)>eps);
printf("%0.2lf",ans);
return 0;
}
好了到这里就结束了。坑点也把我也坑过,这提醒我们要多细想与思考,考虑其特殊性。我就很缺乏这一点。若如有哪里写的不好或写错,敬请各位看官在评论区提出意见。最后,送读者们(虽然并不多)一句话,虽然已经听过多次:
细节决定成败!
现今听来,仍是觉得荡气回肠,掷地有声!
P2571 [SCOI2010]传送带——hyl天梦的更多相关文章
- P2571 [SCOI2010]传送带
P2571 [SCOI2010]传送带 三分套三分. 前提条件:P3382 [模板]三分法 三分,求区间内单峰函数的最大/最小值. 我们把两条线段都跑三分,先ab后cd,求出最小值. 可以直接将二维坐 ...
- 【解题报告】洛谷 P2571 [SCOI2010]传送带
[解题报告]洛谷 P2571 [SCOI2010]传送带今天无聊,很久没有做过题目了,但是又不想做什么太难的题目,所以就用洛谷随机跳题,跳到了一道题目,感觉好像不是太难. [CSDN链接](https ...
- 洛谷P2571 [SCOI2010]传送带 [三分]
题目传送门 传送带 题目描述 在一个2维平面上有两条传送带,每一条传送带可以看成是一条线段.两条传送带分别为线段AB和线段CD.lxhgww在AB上的移动速度为P,在CD上的移动速度为Q,在平面上的移 ...
- [洛谷P2571] [SCOI2010]传送带
题目描述 在一个2维平面上有两条传送带,每一条传送带可以看成是一条线段.两条传送带分别为线段AB和线段CD.lxhgww在AB上的移动速度为P,在CD上的移动速度为Q,在平面上的移动速度R.现在lxh ...
- 洛谷 P2571 [SCOI2010]传送带 题解
每日一题 day51 打卡 Analysis 这道题是用非常恶心的三分套三分做的,有一个技巧是不要枚举坐标,枚举两条线段构成三角形的相似比就好了. 了解思路就还挺好写的(尽管我还调了三天) #incl ...
- bzoj 1857: [Scoi2010]传送带 三分
题目链接 1857: [Scoi2010]传送带 Time Limit: 1 Sec Memory Limit: 64 MBSubmit: 934 Solved: 501[Submit][Stat ...
- 2018.06.30 BZOJ1857: [Scoi2010]传送带(三分套三分)
1857: [Scoi2010]传送带 Time Limit: 1 Sec Memory Limit: 64 MB Description 在一个2维平面上有两条传送带,每一条传送带可以看成是一条线段 ...
- [SCOI2010]传送带 三分法
[SCOI2010]传送带 LG传送门 三分法模板. 关于为什么可以三分,我选择感性理解,有人证明了,总之我是懒得证了. 假设路径是\(A \to E \to F \to D\),\(E\)和\(F\ ...
- 【BZOJ1857】[Scoi2010]传送带 三分套三分
[BZOJ1857][Scoi2010]传送带 Description 在一个2维平面上有两条传送带,每一条传送带可以看成是一条线段.两条传送带分别为线段AB和线段CD.lxhgww在AB上的移动速度 ...
随机推荐
- 洛谷P1720 月落乌啼算钱 题解 斐波那契数列/特征方程求解
题目链接:https://www.luogu.com.cn/problem/P1720 题目描述: 给你一个公式 ,求对应的 \(F_n\) . 解题思路: 首先不难想象这是一个斐波那契数列,我们可以 ...
- 「Luogu P3866」[TJOI2009]战争游戏 解题报告
题面 好难表述啊~ 在n*m的矩阵上,有一些大兵(为0),一些空地(一个正整数),障碍物(-1),现在摧毁一些空地,使所有大兵不能走出矩阵去(代价为表示空地的整数),求最小代价 思路: 网络流最小割 ...
- 「BZOJ4510」「Usaco2016 Jan」Radio Contact 解题报告
无线电联系 Radio Contact 题目描述 Farmer John has lost his favorite cow bell, and Bessie the cow has agreed t ...
- xshell连接kali linux虚拟机
这次测试一波三折 刚开始在百度经验看的先修改ssh参数,蓝色的字是百度的,重点都在图片上 1.修改sshd_config文件,命令为: vi /etc/ssh/sshd_config 将#Passwo ...
- 【python小随笔】将一个列表的值,分成10个一组,遍历的时候每10个遍历一次
t = ['B071LF9R6G', 'B0714BP3H4', 'B0756FL8R7', 'B072HX95ZR', 'B07CX389LX', 'B07D9MZ7BD', 'B07D9L15L5 ...
- 欧拉-拉格朗日方程 The Euler-Lagrange Equation
在 paper: Bounded Biharmonic Weights for Real-Time Deformation 中第一次接触到 Euler-Lagrange 方程,简单记录一下. 泛函的定 ...
- 小白学 Python 爬虫(37):爬虫框架 Scrapy 入门基础(五) Spider Middleware
人生苦短,我用 Python 前文传送门: 小白学 Python 爬虫(1):开篇 小白学 Python 爬虫(2):前置准备(一)基本类库的安装 小白学 Python 爬虫(3):前置准备(二)Li ...
- JVM之堆的体系结构
一.堆的体系结构 Heap 堆一个JVM 实例只存在一个堆内存,堆内存的大小是可以调节的.类加载器读取了类字节码文件后,需要把类.方法.常量.变最放到堆内存中,保存所有引用类型的真实信息,以便执行器执 ...
- Java 集合的工具类Collections的常用方法
Collections类 java.utils.Collections是集合工具类,用来对集合进行操作. Collections类的常用方法 这里介绍四个常用方法: addAll(Collection ...
- acmPush模块示例demo
感谢论坛版主 马浩川 的分享. 模块介绍: 阿里移动推送(Alibaba Cloud Mobile Push)是基于大数据的移动智能推送服务,帮助App快速集成移动推送的功能,在实现高效.精确.实时 ...