1439:【SCOI2010】传送带
1439:【SCOI2010】传送带(一本通网站原题链接)
【分析】
这个题目其实我想的比较简单,问题的决策点在于何时离开第一个传送带,何时上第二个传送带。两个决策点可变为一个决策问题用两次。我们把这个问题换一个说法。你在笔直的河岸边发现河中一人求救,己知你水中速度和岸上速度,求你到达求救者的最短时间。那这个决策就是你在何处下水。这问题用一个极限思考:河岸看作足够长,在河岸的两端入水,到达时间都是很大,当向中点某点靠近时,这个时间在缩小。换言之,把河岸看作一个坐标轴,入水点与你所在位置的差为自变量x,那函数值时间t是x的一个函数,这个函数的单调性为先减后增型(实质是一个单峰函数),那解决它的办法就是三分法。回到本题,我们的策略可以这样描述:先把第一个传送带三分,分点分别为A、B。选择A还是B那将取决于从哪里下传送带更快。这个快与慢还需要第二次决策:从哪里上第二个传送带。我们可以先用三分法算出从A下传送带的最快时间,同样三分法算出从B下传送带的最快时间,那我们就知道A、B两点我们选择哪一点了。接着就是把A、B的距离无限靠近就好。注意,本题有一个特殊情形,我们的思路是两个三分法嵌套,外层最好用do循环,否则外层中传送带长度为0直接就不进入循环了。
【AC代码】
(说明:为了熟悉下结构体重载,我选择了用结构体,具体实现方法因你而改变)
//1439:【SCOI2010】传送带 #include<iostream> #include<cmath> #include<iomanip> using namespace std; struct point{ double x,y; void operator = (const point p) { //point t; x=p.x; y=p.y; //return t; } point operator * (const int n) { point t; t.x=x*n,t.y=y*n; return t; } point operator / (const int n) { point t; t.x=x/n,t.y=y/n; return t; } point operator +(const point p) { point t; t.x=x+p.x,t.y=y+p.y; return t; } }a[4],b[4],md[4]; double q,p,r; double dis(point w,point e) { double h,v,s; h=w.x-e.x; v=w.y-e.y; s=sqrt(h*h+v*v); //cout<<w.x<<' '<<w.y<<' '<<e.x<<' '<<e.y<<' '<<s<<endl; return s; } double jl(int m,int n) { double s=0; s+=dis(a[0],md[m])/p; s+=dis(md[m],md[n])/r; s+=dis(md[n],a[3])/q; return s; } void pr(point w) { cout<<w.x<<' '<<w.y<<endl; } int main(){ for(int i=0;i<4;i++)cin>>a[i].x>>a[i].y; cin>>p>>q>>r; b[0]=a[0],b[1]=a[1]; do { md[0]=(b[0]*2+b[1])/3; md[1]=(b[0]+b[1]*2)/3; b[2]=a[2],b[3]=a[3]; while(dis(b[2],b[3])>1e-11) { md[2]=(b[2]*2+b[3])/3; md[3]=(b[2]+b[3]*2)/3; if(jl(0,2)<jl(0,3))b[3]=md[3]; else b[2]=md[2]; } if(jl(0,3)<jl(1,3))b[1]=md[1]; else b[0]=md[0]; }while(dis(b[0],b[1])>1e-11); cout<<fixed<<setprecision(2)<<jl(0,2); return 0; }