P2571 [SCOI2010]传送带题解————天梦

如写的不好,请多见谅。

对于这道题,我首先想说,确实困惑了我好久,看网上的各种题解,却都不尽人意,思路早已明白,却不会操作。最后想想,还是觉得自己试着写一个吧。一种思路,与题解的思路不同,但理论上可行,但我当时似乎也不太相信那所谓的“理论”,毕竟自己错过许多次,即使这样仍要相信自己吗?想着,便已经翻到了我所需要的——与自己思路相同的题解。网址是https://blog.csdn.net/qq_42920122/article/details/88622782,什么思路呢?,在这之前,我建议大家,一定要相信自己,接下来让我们一起往下看。

题目

参考网址https://www.luogu.com.cn/problem/P2571

引入

现在请各位读者先抛开这个题,先想这样一个问题,如果在一个平面上,有一个点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就可以了。详细看代码。

代码

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cmath>
  4. #include<algorithm>
  5. #include<cstring>
  6. #include<sstream>
  7. #include<queue>
  8. #include<map>
  9. #include<vector>
  10. #include<set>
  11. #include<deque>
  12. #define dd double
  13. #define ll long long
  14. #define N 10000100
  15. using namespace std;
  16. dd ans=N;
  17. struct point{
  18. dd x,y;//存点的坐标
  19. };
  20. point a,b,c,d;
  21. int p,q,r;
  22. const dd eps=1e-8;//精度,我比较习惯于开1e-8;
  23. dd dis(point l,point r)
  24. {
  25. return sqrt((l.x-r.x)*(l.x-r.x)+(l.y-r.y)*(l.y-r.y));
  26. }//求点l到点r的距离,勾股定理
  27. dd f(point mid2,point midmid)
  28. {
  29. return dis(mid2,midmid)/r+dis(midmid,d)/q;
  30. }//这个函数是对于AB上的点mid2和在CD上的点midmid,求一下从mid到midmid和midmid到点d的“时间”;
  31. dd Three_CD(point mid2)//三分CD,mid2是已将选好的“E”
  32. {
  33. dd zanans=N;
  34. point l,r; l.x=c.x; l.y=c.y; r.x=d.x; r.y=d.y;
  35. while(dis(l,r)>eps)
  36. {
  37. point mid,midmid;
  38. mid.x=(l.x+r.x)/2.0; mid.y=(l.y+r.y)/2.0;
  39. midmid.x=(mid.x+r.x)/2.0; midmid.y=(mid.y+r.y)/2.0;
  40. if(f(mid2,mid)<f(mid2,midmid))
  41. {
  42. zanans=min(ans,f(mid2,mid));
  43. r=midmid;
  44. }
  45. else
  46. {
  47. zanans=min(ans,f(mid2,midmid));
  48. l=mid;
  49. }
  50. }
  51. return zanans;
  52. }
  53. int main()
  54. {
  55. cin>>a.x>>a.y>>b.x>>b.y>>c.x>>c.y>>d.x>>d.y>>p>>q>>r;
  56. point l,r; l.x=a.x; l.y=a.y; r.x=b.x; r.y=b.y;
  57. while(dis(l,r)>eps)//三分AB
  58. {
  59. point mid,midmid;
  60. mid.x=(l.x+r.x)/2.0; mid.y=(l.y+r.y)/2.0;
  61. midmid.x=(mid.x+r.x)/2.0; midmid.y=(mid.y+r.y)/2.0;
  62. dd ans1=Three_CD(mid);
  63. dd ans2=Three_CD(midmid);//ans1是以mid为E的最优解,ans2同理,看着两个值哪个最优。
  64. //cout<<ans1<<" "<<ans2<<" ";
  65. ans1=ans1+dis(a,mid)/p;
  66. ans2=ans2+dis(a,midmid)/p;
  67. //cout<<ans1<<" "<<ans2<<" ";
  68. if(ans1<ans2)
  69. {
  70. ans=min(ans,ans1);
  71. r=midmid;
  72. }
  73. else
  74. {
  75. ans=min(ans,ans2);
  76. l=mid;
  77. }//更新ans
  78. //printf("%0.2lf\n",ans);
  79. }
  80. printf("%0.2lf",ans);
  81. return 0;
  82. }

你以为这就完了,不,没有!

坑点

请大家仔细想想,如若A、B两点重合,会怎么样?ans将会是N!C、D重合是一个道理。do-while可以很好地解决这个问题。

真正AC代码(无注释)

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cmath>
  4. #include<algorithm>
  5. #include<cstring>
  6. #include<sstream>
  7. #include<queue>
  8. #include<map>
  9. #include<vector>
  10. #include<set>
  11. #include<deque>
  12. #define dd double
  13. #define ll long long
  14. #define N 10000100
  15. using namespace std;
  16. dd ans=N;
  17. struct point{
  18. dd x,y;
  19. };
  20. point a,b,c,d;
  21. int p,q,r;
  22. const dd eps=1e-8;
  23. dd dis(point l,point r)
  24. {
  25. return sqrt((l.x-r.x)*(l.x-r.x)+(l.y-r.y)*(l.y-r.y));
  26. }
  27. dd f(point mid2,point midmid)
  28. {
  29. return dis(mid2,midmid)/r+dis(midmid,d)/q;
  30. }
  31. dd Three_CD(point mid2)
  32. {
  33. dd zanans=N;
  34. point l,r; l.x=c.x; l.y=c.y; r.x=d.x; r.y=d.y;
  35. do
  36. {
  37. point mid,midmid;
  38. mid.x=(l.x+r.x)/2.0; mid.y=(l.y+r.y)/2.0;
  39. midmid.x=(mid.x+r.x)/2.0; midmid.y=(mid.y+r.y)/2.0;
  40. if(f(mid2,mid)<f(mid2,midmid))
  41. {
  42. zanans=min(ans,f(mid2,mid));
  43. r=midmid;
  44. }
  45. else
  46. {
  47. zanans=min(ans,f(mid2,midmid));
  48. l=mid;
  49. }
  50. }
  51. while(dis(l,r)>eps);
  52. return zanans;
  53. }
  54. int main()
  55. {
  56. cin>>a.x>>a.y>>b.x>>b.y>>c.x>>c.y>>d.x>>d.y>>p>>q>>r;
  57. point l,r; l.x=a.x; l.y=a.y; r.x=b.x; r.y=b.y;
  58. do
  59. {
  60. point mid,midmid;
  61. mid.x=(l.x+r.x)/2.0; mid.y=(l.y+r.y)/2.0;
  62. midmid.x=(mid.x+r.x)/2.0; midmid.y=(mid.y+r.y)/2.0;
  63. dd ans1=Three_CD(mid);
  64. dd ans2=Three_CD(midmid);
  65. //cout<<ans1<<" "<<ans2<<" ";
  66. ans1=ans1+dis(a,mid)/p;
  67. ans2=ans2+dis(a,midmid)/p;
  68. //cout<<ans1<<" "<<ans2<<" ";
  69. if(ans1<ans2)
  70. {
  71. ans=min(ans,ans1);
  72. r=midmid;
  73. }
  74. else
  75. {
  76. ans=min(ans,ans2);
  77. l=mid;
  78. }
  79. //printf("%0.2lf\n",ans);
  80. }while(dis(l,r)>eps);
  81. printf("%0.2lf",ans);
  82. return 0;
  83. }

好了到这里就结束了。坑点也把我也坑过,这提醒我们要多细想与思考,考虑其特殊性。我就很缺乏这一点。若如有哪里写的不好或写错,敬请各位看官在评论区提出意见。最后,送读者们(虽然并不多)一句话,虽然已经听过多次:

细节决定成败!

现今听来,仍是觉得荡气回肠,掷地有声!

P2571 [SCOI2010]传送带——hyl天梦的更多相关文章

  1. P2571 [SCOI2010]传送带

    P2571 [SCOI2010]传送带 三分套三分. 前提条件:P3382 [模板]三分法 三分,求区间内单峰函数的最大/最小值. 我们把两条线段都跑三分,先ab后cd,求出最小值. 可以直接将二维坐 ...

  2. 【解题报告】洛谷 P2571 [SCOI2010]传送带

    [解题报告]洛谷 P2571 [SCOI2010]传送带今天无聊,很久没有做过题目了,但是又不想做什么太难的题目,所以就用洛谷随机跳题,跳到了一道题目,感觉好像不是太难. [CSDN链接](https ...

  3. 洛谷P2571 [SCOI2010]传送带 [三分]

    题目传送门 传送带 题目描述 在一个2维平面上有两条传送带,每一条传送带可以看成是一条线段.两条传送带分别为线段AB和线段CD.lxhgww在AB上的移动速度为P,在CD上的移动速度为Q,在平面上的移 ...

  4. [洛谷P2571] [SCOI2010]传送带

    题目描述 在一个2维平面上有两条传送带,每一条传送带可以看成是一条线段.两条传送带分别为线段AB和线段CD.lxhgww在AB上的移动速度为P,在CD上的移动速度为Q,在平面上的移动速度R.现在lxh ...

  5. 洛谷 P2571 [SCOI2010]传送带 题解

    每日一题 day51 打卡 Analysis 这道题是用非常恶心的三分套三分做的,有一个技巧是不要枚举坐标,枚举两条线段构成三角形的相似比就好了. 了解思路就还挺好写的(尽管我还调了三天) #incl ...

  6. bzoj 1857: [Scoi2010]传送带 三分

    题目链接 1857: [Scoi2010]传送带 Time Limit: 1 Sec  Memory Limit: 64 MBSubmit: 934  Solved: 501[Submit][Stat ...

  7. 2018.06.30 BZOJ1857: [Scoi2010]传送带(三分套三分)

    1857: [Scoi2010]传送带 Time Limit: 1 Sec Memory Limit: 64 MB Description 在一个2维平面上有两条传送带,每一条传送带可以看成是一条线段 ...

  8. [SCOI2010]传送带 三分法

    [SCOI2010]传送带 LG传送门 三分法模板. 关于为什么可以三分,我选择感性理解,有人证明了,总之我是懒得证了. 假设路径是\(A \to E \to F \to D\),\(E\)和\(F\ ...

  9. 【BZOJ1857】[Scoi2010]传送带 三分套三分

    [BZOJ1857][Scoi2010]传送带 Description 在一个2维平面上有两条传送带,每一条传送带可以看成是一条线段.两条传送带分别为线段AB和线段CD.lxhgww在AB上的移动速度 ...

随机推荐

  1. 「CF242E」XOR on Segment 解题报告

    题面 长度为\(n\)的数列,现有两种操作: 1.区间异或操作 2.区间求和操作 对于每个查询,输出答案 思路: 线段树+二进制拆位 线段树区间修改一般使用的都是懒标记的方法,但是对于异或,懒标记的方 ...

  2. Django之表高级操作

    目录 一.如何开启自己的测试脚本? 二.对表数据的添加.更新.删除 1.create() 2.update() 3.delete() 4.查看执行的sql语句 三. 单表查询13个操作 返回Query ...

  3. Maven聚合工程安装时排除掉不参与本次安装的子工程

    为解决本人在练习项目时的实际需求而做此记录: 在练习SSM项目时,通过Maven的聚合工程搭建了几个module,通过 health_parent 父工程进行管理,内有 healthmobile_we ...

  4. SpringBoot-2.1.1系列一:使用https

    1.什么是https? HTTPS中文名称:超文本传输安全协议,是以安全为目标的HTTP通道,简单讲是HTTP的安全版.即HTTP下加入SSL层,HTTPS的安全基础是SSL,因此加密的详细内容就需要 ...

  5. cannot open git-upload-pack,cannot open git-receive-pack,Can't connect to any URI错误解决方法eclipse

    cannot open git-upload-pack,cannot open git-receive-pack,Can't connect to any URI错误解决方法eclipse 解决ecl ...

  6. Python学到什么程度可以面试工作(解答一)

    本文整理了 26 个 Python 有用的技巧,将按照首字母从 A~Z 的顺序分享其中一些内容. all 或 any 人们经常开玩笑说 Python 是“可执行的伪代码”,但是当你可以这样编写代码时, ...

  7. 拥有 GitHub 开源项目的小伙伴,免费申请 JetBrains 全家桶的全流程详解

    工欲善其事,必先利其器.如果您想要学习 Java.PHP.Ruby.Python.JavaScript.Objective-C..NET 中的任何一种开发技术,国际知名且屡获殊荣的 JetBrains ...

  8. MapInfo常见数据格式

    在MapInfo 中所指的表是单纯的数据表或是图形与数据的结合.一个典型的MapInfo表将主要由*.tab.*.dat.*.wks.*.dbf.*.xls.*.map.*.id.*.ind文件格式组 ...

  9. Go Web 编程之 静态文件

    概述 在 Web 开发中,需要处理很多静态资源文件,如 css/js 和图片文件等.本文将介绍在 Go 语言中如何处理文件请求. 接下来,我们将介绍两种处理文件请求的方式:原始方式和http.File ...

  10. Inception V1、V2、V3和V4

    Inception模块分为V1.V2.V3和V4. V1(GoogLeNet)的介绍 论文:Going deeper with convolutions 论文链接:https://arxiv.org/ ...