「一本通 1.2 练习 4」传送带
zhangjianweivv · · 题解
这道题真的很难想到思路,但是想到了也很难实现,最后是以一种很神奇的思路搞定的、、
传送门
其实一开始真的想不到,是看了大佬的题解才想出来的。思路其实不难理解,目前我接触到了三种思路。
一、三分
1.三分坐标
这是最常见的思路了,很多大佬都是用三分坐标的(包括猴子大佬),因为很好理解。
我们进行三分套三分,把线段
具体三分方法在图里有说。代码详见loj评测找zhangjianjunab。
2.三分比例
这是我的思路了、、虽然好像没什么人用、、
我原本的思路是三分与
后来上网看了大佬的博客,发现可以三分比值。具体如下:
我们现在已知线段
以
所以
所以我们可以直接三分
同样的方法三分线段
贴个代码、、
#include<cmath>
#include<cstdio>
#include<cstring>
using namespace std;
struct node
{
double x,y;
}a,b,c,d;double p,q,r;
double gougu(node n1,node n2)
{
return sqrt((n1.x-n2.x)*(n1.x-n2.x)+(n1.y-n2.y)*(n1.y-n2.y));
}
node find(node xx,node yy,double k)
{
node no;no.x=(yy.x-xx.x)*k+xx.x;no.y=(yy.y-xx.y)*k+xx.y;
return no;
}
double checkplus(double x,double y)
{
node n1=find(a,b,x),n2=find(c,d,y);
return gougu(a,n1)/p+gougu(n1,n2)/r+gougu(n2,d)/q;
}
double check(double x)
{
double l=0.0,r=1.0;
while(r-l>=0.0000001)
{
double mid1=l+(r-l)/3.0,mid2=r-(r-l)/3.0;
if(checkplus(x,mid1)>checkplus(x,mid2))l=mid1;
else r=mid2;
}
return checkplus(x,l);
}
int main()
{
scanf("%lf%lf%lf%lf",&a.x,&a.y,&b.x,&b.y);
scanf("%lf%lf%lf%lf",&c.x,&c.y,&d.x,&d.y);
scanf("%lf%lf%lf",&p,&q,&r);
double l=0.0,r=1.0;
while(r-l>=0.0000001)
{
double mid1=l+(r-l)/3.0,mid2=r-(r-l)/3.0;
if(check(mid1)>check(mid2))l=mid1;
else r=mid2;
}
printf("%.2lf",check(l));
return 0;
}
(当然,由于懒,所有inline都没有加、、)
二、模拟退火
我也不知道这是什么(太菜了、、),可以上网搜一搜。
三、暴力搜
这个好像也能过几个点?不过两位小数,的确也可以暴力找。也有大佬是先暴力在
三分单峰函数证明
今天上午才听猴子证了这个,觉得自己学算法还是太浅了,要知道为什么可以用三分才行。
首先,我们画一个图。假设上面的点为线段
而
我们可以看出,
但是一般来说,
所以我们可以找到一条路径,使其左边的都为因为懒不想证)
好就写到这里(累死我了)