信息学奥赛一本通 提高篇 提高版 第一部分 基础算法 第2章 二分与三分
//二分法,最经典的例子,就是求平方根。
//2
//1.414
//3
//1.732
//程序执行效果如下,2018-10-15 21:04
#include <stdio.h>
#define eps 1e-12
double sqrt(double x){
double left=0,right=x,mid;
while(left+eps<right){
mid=(left+right)/2;
if(mid*mid<x)left=mid;
else right=mid;
}
return right;
}
int main(){
double d;
scanf("%lf",&d);
printf("%lf\n",sqrt(d));
return 0;
}
#10011 「一本通 1.2 例 1」愤怒的牛
//#10011 「一本通 1.2 例 1」愤怒的牛
//在线测评地址https://loj.ac/problem/10011
//该题与 1247:河中跳房子 思路基本一致http://ybt.ssoier.cn:8088/problem_show.php?pid=1247在线测评地址
//模拟如下,先排序1 2 4 8 9 left=0 right=9-1=8 mid=(left+right)/2=4
//x=4 剩1 8两个牛舍,太少故right=4 left=0 mid=(left+right)/2=2
//x=2 剩1 4 8三个牛舍,不大于3个牛舍,left=2 right=4 mid=(left+right)/2=3
//x=3 剩1 4 8三个牛舍,不大于3个牛舍,left=3 right=4 left+1<right 循环结束
//样例通过,提交AC。2018-10-5 08:06
#include <cstdio>
#include <algorithm>
using namespace std;
int a[100100],n,m;
int judge(int x){//牛舍数量过多或刚好left=mid 返回1 牛舍数量过少right=mid返回0
int i,pre,cnt;//cnt统计剩下的牛舍数量
pre=1,cnt=1;//pre保存符合条件,最近选用的牛舍序号
for(i=2;i<=n;i++)
if(a[i]-a[pre]>=x)
cnt++,pre=i;
if(cnt<m)return 0;
return 1;
}
int main(){
int i,left,right,mid;
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)scanf("%d",&a[i]);
sort(a+1,a+n+1);
left=0,right=a[n]-a[1];
while(left+1<right){
mid=(left+right)/2;
if(judge(mid))left=mid;
else right=mid;
}
printf("%d\n",left);
}
#10012 「一本通 1.2 例 2」Best Cow Fences
//#10012. 「一本通 1.2 例 2」Best Cow Fences
//在线测评地址https://loj.ac/problem/10012
//在线测评地址https://vjudge.net/problem/POJ-2018
//样例理解如下:
//前缀和,想到了,用也仅能用在O(n^2)时间复杂度上
//https://blog.csdn.net/Coldfresh/article/details/79617912此文注释写得棒,代码值得读
//通过本题,对二分有了更深的认识。2018-10-5 16:01
//样例通过,提交Wrong Answer.
//修改,double min_left=1e10,ans=-1e10;//此处写成min_left=1e6,ans=-2e8 ,提交Wrong Answer.
//该题在提交过程中,最难的还是输出部分的处理。 printf("%d\n",(int)(right*1000));//此处写成printf("%.0lf\n",right*1000);//此处写成printf("%d\n",(int)(left*1000));//此处写成 printf("%.0lf\n",left*1000);
//修改,提交AC。2018-10-5 16:45
#include <stdio.h>
#define maxn 100100
#define eps 1e-6
double a[maxn],b[maxn],c[maxn];
int n,L;
double min(double a,double b){
return a<b?a:b;
}
double max(double a,double b){
return a>b?a:b;
}
int judge(double x){
int i;
double min_left=1e10,ans=-1e10;//此处写成min_left=1e6,ans=-2e8//此处写成 ans=1e-6
for(i=1;i<=n;i++)b[i]=a[i]-x;
c[0]=0;
for(i=1;i<=n;i++)c[i]=c[i-1]+b[i];
for(i=L;i<=n;i++){
min_left=min(min_left,c[i-L]);//计算最小的左端点
ans=max(ans,c[i]-min_left);//计算最大的和
}
if(ans<0)return 0;//mid取得过大,right=mid
else return 1;
}
int main(){
int i;
double left=1e6,right=-1e6,mid;
scanf("%d%d",&n,&L);
for(i=1;i<=n;i++){
scanf("%lf",&a[i]);
left=min(left,a[i]);
right=max(right,a[i]);
}
while(left+eps<right){
mid=(left+right)/2;
if(judge(mid))
left=mid;
else
right=mid;
}
printf("%d\n",(int)(right*1000));//此处写成printf("%.0lf\n",right*1000);//此处写成printf("%d\n",(int)(left*1000));//此处写成 printf("%.0lf\n",left*1000);
return 0;
}
#10013 「一本通 1.2 例 3」曲线
//#10013. 「一本通 1.2 例 3」曲线
//在线测评地址https://loj.ac/problem/10013
//在线测评地址https://vjudge.net/problem/UVA-1476
//在线测评地址https://vjudge.net/problem/HDU-3714
//题意确实没明白,实则样例没有弄懂。
//https://blog.csdn.net/zuihoudebingwen/article/details/8037089该文说得不错,摘抄如下:
//读题读了好久,汗。。就是给你n个二次函数,定义域为[0,1000],
//求x在定义域中每个x所在的n个函数的最大值的最小值。
//有二次函数的性质,很明显不的三分题。。。
//为了帮助大家理解该题,特别绘制了第二组数据对应的图形,及输出结果0.5000的由来
//不了解 三分 的,可以通过此文了解三分。https://blog.csdn.net/pi9nc/article/details/9666627
//样例通过,提交Wrong Answer.
//查了半天,发现是精度问题, #define eps 1e-12//此处写成 #define eps 1e-6
//修改,提交AC。2018-10-6 12:48
#include <stdio.h>
#define maxn 100100
#define eps 1e-12//此处写成 #define eps 1e-6
double a[maxn],b[maxn],c[maxn];
double max(double a,double b){
return a>b?a:b;
}
double S(double a,double b,double c,double x){
return a*x*x+b*x+c;
}
double F(int n,double x){
int i;
double ans=-1e10;
for(i=1;i<=n;i++)
ans=max(ans,S(a[i],b[i],c[i],x));
return ans;
}
int main(){
int T,n,i;
double left,mid,mmid,right;
scanf("%d",&T);
while(T--){
scanf("%d",&n);
for(i=1;i<=n;i++)
scanf("%lf%lf%lf",&a[i],&b[i],&c[i]);
left=0,right=1000;
while(left+eps<right){
mid=(left+right)/2,mmid=(mid+right)/2;
if(F(n,mid)<F(n,mmid))
right=mmid;
else
left=mid;
}
printf("%.4lf\n",F(n,left));
}
return 0;
}
#10014 「一本通 1.2 练习 1」数列分段 II
//#10014. 「一本通 1.2 练习 1」数列分段 II
//在线测评地址https://loj.ac/problem/10014
//在线测评地址https://www.luogu.org/problemnew/show/P1182
//样例模拟如下
//4 2 4 5 1
//left=5 right=16 mid=10 [4 2 4][5 1] section=2 right=mid
//left=5 right=10 mid=7 [4 2][4][5 1] section=3 right=mid
//left=5 right=7 mid=6 [4 2][4][5 1] section=3 right=mid
//left=5 right=6 left+1<right 循环结束
//二分法,最后结果输出是left,还是right,模拟是关键
//样例通过,提交Wrong Answer.
//修改,int section=1,sum=0,i;//此处写成 section=0 一开始就是一段
//提交, https://www.luogu.org/problemnew/show/P1182中测试点4,WA。
//决定重新模拟样例
//4 2 4 5 1
//left=5 right=16 mid=10 [4 2 4][5 1] section=2 right=mid
//left=5 right=10 mid=7 [4 2][4][5 1] section=3 right=mid
//left=5 right=7 mid=6 [4 2][4][5 1] section=3 right=mid
//for(i=left;i<=right;i++)//一直被选left还是right所困扰,今日学得一招,真是管用2018-10-6 19:57
//https://www.luogu.org/discuss/show?postid=17784参考此文代码,习得上述技巧。
//提交,AC。2018-10-6 19:57
//https://loj.ac/problem/10014提交,AC。2018-10-6 20:10
#include <stdio.h>
int n,m,a[1000100];
int max(int a,int b){
return a>b?a:b;
}
int judge(int x){//section<=m right=mid 1否则 left=mid 0
int section=1,sum=0,i;//此处写成 section=0 一开始就是一段
for(i=1;i<=n;i++){
sum+=a[i];
if(sum>x){
sum=a[i];
section++;
}
}
if(section<=m)return 1;
else return 0;
}
int main(){
int i,left=-1,right=0,mid;
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++){
scanf("%d",&a[i]);
left=max(left,a[i]);
right+=a[i];
}
while(left+1<right){
mid=(left+right)/2;
if(judge(mid))right=mid;
else left=mid;
}
//此处写成printf("%d\n",right);
for(i=left;i<=right;i++)//一直被选left还是right所困扰,今日学得一招,真是管用2018-10-6 19:57
if(judge(i)){
left=i;
break;
}
printf("%d\n",left);
return 0;
}
#10015 「一本通 1.2 练习 2」扩散
方法一:Floyd算法
//#10015. 「一本通 1.2 练习 2」扩散
//在线测评地址https://loj.ac/problem/10015
//在线测评地址https://www.luogu.org/problemnew/show/P1661
//样例执行过程,如下图:
//((5-0)+(5-0)+1)/2=5
//https://baike.baidu.com/item/%E6%9B%BC%E5%93%88%E9%A1%BF%E8%B7%9D%E7%A6%BB/743092?fr=aladdin了解了曼哈顿距离
//试着举几个例子,找找规律
//输入:
//2
//0 0
//1 2
//输出:
//2
//样例执行过程如下:
//((1-0)+(2-0)+1)/2=2
//两个例子的计算中,均出现了曼哈顿距离。+1是为了适应奇数距离,/2是因为两个点同时增长。2018-10-7 19:40
//方法一:采用Floyd算法,将各点之间最短距离算一遍;
//第二步,在各点间最短距离中找最大距离,即为答案。
//看了,该题,x,y的数据范围,感觉采用int是在刀尖上行走,决定采用long long
//样例通过,提交WA。
//发现,将Floyd的循环顺序写错,for(k=1;k<=n;k++)//以k点为中介,进行查找//将该循环写到了最内层。修改,提交WA。
//发现,if(map[i][j]!=((LL)1<<33)&&ans<map[i][j])//此处写成 if(ans<map[i][j]) 修改,提交WA。
//参考了,https://www.luogu.org/problemnew/solution/P1661
//弄到最后,还是发现,i,j,k三个点时,算法出错了,
//map[i][j]=min(map[i][j],max(map[i][k],map[k][j]));//终归还是要画图模拟//此句写成 if(map[i][j]>map[i][k]+map[k][j])map[i][j]=map[i][k]+map[k][j];
//修改,提交AC。2018-10-7 21:10
#include <stdio.h>
#define LL long long
struct node{
LL x,y;
}point[55];
LL n,map[55][55];
LL abs(LL a){
if(a<0)a=-a;
return a;
}
LL getDist(LL i,LL j){
return (abs(point[i].x-point[j].x)+abs(point[i].y-point[j].y)+1)/2;
}
LL min(LL a,LL b){
return a<b?a:b;
}
LL max(LL a,LL b){
return a>b?a:b;
}
int main(){
LL i,j,k,ans=-1;
scanf("%lld",&n);
for(i=1;i<=n;i++)
scanf("%lld%lld",&point[i].x,&point[i].y);
for(i=1;i<=n;i++)//初始化邻接矩阵
for(j=1;j<=n;j++)
if(i==j)map[i][j]=0;
for(i=1;i<=n;i++)//初始化邻接矩阵
for(j=i+1;j<=n;j++)
map[j][i]=map[i][j]=getDist(i,j);
for(k=1;k<=n;k++)//以k点为中介,进行查找//将该循环写到了最内层。
for(i=1;i<=n;i++)//Floyd算法
for(j=1;j<=n;j++)
map[i][j]=min(map[i][j],max(map[i][k],map[k][j]));//终归还是要画图模拟//此句写成 if(map[i][j]>map[i][k]+map[k][j])map[i][j]=map[i][k]+map[k][j];
for(i=1;i<=n;i++)//找两点间最大距离
for(j=i+1;j<=n;j++)
if(ans<map[i][j])//此处写成 if(ans<map[i][j])
ans=map[i][j];
printf("%lld\n",ans);
return 0;
}
//#10015. 「一本通 1.2 练习 2」扩散
//方法二:Kruskal算法,最小生成树中找最长的边
//样例通过,提交AC。2018-10-8 16:55
//从编程思路及成功率来说,方法二远胜方法一。
#include <cstdio>
#include <algorithm>
#define LL long long
#define maxn 55
LL f[maxn],n,x[maxn],y[maxn],e_cnt=0;
using namespace std;
struct node{
LL i,j;
LL w;
}e[maxn*maxn/2];
LL myAbs(LL a){
if(a<0)a=-a;
return a;
}
LL getDist(LL i,LL j){
return (myAbs(x[i]-x[j])+myAbs(y[i]-y[j])+1)/2;
}
LL cmp(const node &a,const node &b){
return a.w<b.w;
}
LL getFather(LL u){
if(f[u]==u)return u;
return f[u]=getFather(f[u]);
}
LL merge(LL u,LL v){
LL f1=getFather(u),f2=getFather(v);
if(f1==f2)return 0;
f[f2]=f1;//左靠
return 1;
}
int main(){
LL i,j,cnt=0;
scanf("%lld",&n);
for(i=1;i<=n;i++)
scanf("%lld%lld",&x[i],&y[i]);
for(i=1;i<=n;i++)f[i]=i;
for(i=1;i<=n;i++)
for(j=i+1;j<=n;j++){
e_cnt++;
e[e_cnt].i=i,e[e_cnt].j=j;
e[e_cnt].w=getDist(i,j);
}
sort(e+1,e+1+e_cnt,cmp);
for(i=1;i<=e_cnt;i++){
if(merge(e[i].i,e[i].j)){
cnt++;
if(cnt==n-1){
printf("%lld\n",e[i].w);
break;
}
}
}
return 0;
}
//P1661 扩散
//方法三:二分+图的遍历
//图的遍历,图的存储若用邻接矩阵,算法的时间复杂度过高,
//故采用邻接表的方式存储。
//样例通过,提交,https://www.luogu.org/problemnew/show/P1661测试点4,5 RE。
//将 #define maxn 55改成 #define maxn 550,提交AC。
//继续查,查了半天,发现是 e[maxn*maxn]的问题,写成 e[maxn*maxn*10]提交AC。
//不明个中原因,自个造了一组数据,跟踪,才发现,
50
1 1
2 2
3 3
4 4
5 5
6 6
7 7
8 8
9 9
10 10
11 11
12 12
13 13
14 14
15 15
16 16
17 17
18 18
19 19
20 20
21 21
22 22
23 23
24 24
25 25
26 26
27 27
28 28
29 29
30 30
31 31
32 32
33 33
34 34
35 35
36 36
37 37
38 38
39 39
40 40
41 41
42 42
43 43
44 44
45 45
46 46
47 47
48 48
49 49
50 50
//cnt每次也要初始化,没考虑到这个问题,才导致数组越界。
//提交AC。该题,初始化十分关键。2018-10-9
//方法三 优于 方法一
//最优的方法是 方法二
#include <stdio.h>
#include <string.h>
#define maxn 55
#define LL long long
LL head[maxn],cnt,n,x[maxn],y[maxn],map[maxn][maxn],vis[maxn];//此处写成 cnt=0
struct node{
LL to;//边对应的点
LL next;//下一条边
}e[maxn*maxn];
LL min(LL a,LL b){
return a<b?a:b;
}
LL max(LL a,LL b){
return a>b?a:b;
}
void addEdge(LL u,LL v){
cnt++,e[cnt].to=v,e[cnt].next=head[u],head[u]=cnt;
}
LL myAbs(LL a){
if(a<0)a=-a;
return a;
}
LL getDist(LL i,LL j){
return (myAbs(x[i]-x[j])+myAbs(y[i]-y[j])+1)/2;
}
LL judge(LL x){
LL i,j,b,q[maxn],h,t,u,v;
cnt=0;//漏了此句
memset(vis,0,sizeof(vis)),memset(head,0,sizeof(head));
for(i=1;i<=n;i++)//将邻接矩阵 转成 邻接表
for(j=i+1;j<=n;j++)
if(map[i][j]<=x)
addEdge(i,j),addEdge(j,i);
h=t=1,q[t]=1,vis[1]=1,t++;//广度优先遍历
while(h<t){
u=q[h];
b=head[u];
while(b){
v=e[b].to;
if(vis[v]==0)
q[t]=v,vis[v]=1,t++;
b=e[b].next;
}
h++;
}
for(i=1;i<=n;i++)
if(vis[i]==0)return 0;//距离太小
return 1;//距离太长或刚好。
}
int main(){
LL i,j,left=2000000000,right=-1,mid;//p_cnt点的个数
memset(map,0,sizeof(map));
scanf("%lld",&n);
for(i=1;i<=n;i++)scanf("%lld%lld",&x[i],&y[i]);
for(i=1;i<=n;i++)
for(j=i+1;j<=n;j++)
map[j][i]=map[i][j]=getDist(i,j);
for(i=1;i<=n;i++)
for(j=i+1;j<=n;j++){
left=min(left,map[i][j]);
right=max(right,map[i][j]);
}
while(left+1<right){
mid=(left+right)/2;
if(judge(mid))right=mid;
else left=mid;
}
printf("%lld\n",right);
return 0;
}
//方法四:二分+图的遍历
//图的遍历采用 深度优先遍历
//样例通过,提交AC。2018-10-9 21:11
#include <stdio.h>
#include <string.h>
#define maxn 55
#define LL long long
LL head[maxn],cnt,n,x[maxn],y[maxn],map[maxn][maxn],vis[maxn];//此处写成 cnt=0
struct node{
LL to;//边对应的点
LL next;//下一条边
}e[maxn*maxn];
LL min(LL a,LL b){
return a<b?a:b;
}
LL max(LL a,LL b){
return a>b?a:b;
}
void addEdge(LL u,LL v){
cnt++,e[cnt].to=v,e[cnt].next=head[u],head[u]=cnt;
}
LL myAbs(LL a){
if(a<0)a=-a;
return a;
}
LL getDist(LL i,LL j){
return (myAbs(x[i]-x[j])+myAbs(y[i]-y[j])+1)/2;
}
void dfs(LL u){
LL b,v;
b=head[u];
while(b){
v=e[b].to;
if(vis[v]==0){
vis[v]=1;
dfs(v);
}
b=e[b].next;
}
}
LL judge(LL x){
LL i,j;
cnt=0;//漏了此句
memset(vis,0,sizeof(vis)),memset(head,0,sizeof(head));
for(i=1;i<=n;i++)//将邻接矩阵 转成 邻接表
for(j=i+1;j<=n;j++)
if(map[i][j]<=x)
addEdge(i,j),addEdge(j,i);
vis[1]=1;//深度优先遍历
dfs(1);
for(i=1;i<=n;i++)
if(vis[i]==0)return 0;//距离太小
return 1;//距离太长或刚好。
}
int main(){
LL i,j,left=2000000000,right=-1,mid;//p_cnt点的个数
memset(map,0,sizeof(map));
scanf("%lld",&n);
for(i=1;i<=n;i++)scanf("%lld%lld",&x[i],&y[i]);
for(i=1;i<=n;i++)
for(j=i+1;j<=n;j++)
map[j][i]=map[i][j]=getDist(i,j);
for(i=1;i<=n;i++)
for(j=i+1;j<=n;j++){
left=min(left,map[i][j]);
right=max(right,map[i][j]);
}
while(left+1<right){
mid=(left+right)/2;
if(judge(mid))right=mid;
else left=mid;
}
printf("%lld\n",right);
return 0;
}
#10016 「一本通 1.2 练习 3」灯泡
//Light Bulb ZOJ - 3203
//#10016. 「一本通 1.2 练习 3」灯泡
//在线测评地址https://loj.ac/problem/10016
//在线测评地址https://vjudge.net/problem/ZOJ-3203
//人距灯泡的水平距离为x,推导L与x的关系
//从公式上,可以看出,L是关于x的类开口向下的抛物线(凸形更精准)
//找最大值,采用三分。
//算出影长公式,编好程序,设人距灯的水平距离为x,L=D-x+(x*H-D*(H-h))/x,测试
//发现样例中2 0.5 3这组数据对不上
//参看https://blog.csdn.net/scf0920/article/details/46050863代码
//发现是左边界没选好,不能随意的选个0
//参看https://blog.csdn.net/Baiyi_destroyer/article/details/79718020才明白左边界的得出,摘抄如下
//设人距灯的距离为x,从灯正下方走到影子正好到墙角,影子的长度不断增加,此时由相似三角形得影子长度为D-h*D/H;
//left=D-D*h/H,right=D;//此处写成 left=0,造成 2 0.5 3 输出一直对不上
//该题最大的难点在于,影长要分段讨论
//影子只在地上时,随着x是逐渐增大;在地上与墙上时,是一个凸形函数。
//样例终于通过,提交AC。2018-10-10 19:45
#include <stdio.h>
#define eps 1e-12
double H,h,D;
double L(double x){
return D-x+(x*H-D*(H-h))/x;
}
int main(){
int T;
double left,right,mid,mmid;
scanf("%d",&T);
while(T--){
scanf("%lf%lf%lf",&H,&h,&D);
left=D-D*h/H,right=D;//此处写成 left=0,造成 2 0.5 3 输出一直对不上
while(left+eps<right){
mid=(left+right)/2;
mmid=(mid+right)/2;
if(L(mid)>L(mmid))right=mmid;
else left=mid;
}
printf("%.3lf\n",L(left));
}
return 0;
}
//Light Bulb ZOJ - 3203
//受https://blog.csdn.net/jingqi814/article/details/11993565启发
//方法二,求导,
//但发现2 1 0.5;2 0.5 3两组数据均未对上。
//仔细想了想,还是边界的问题。
//跟踪了样例数据,证实了猜想。
//样例通过,提交AC。2018-10-10 21:00
#include <stdio.h>
#include <math.h>
int main(){
int T;
double H,h,D,x,L,left,right;
scanf("%d",&T);
while(T--){
scanf("%lf%lf%lf",&H,&h,&D);
x=sqrt(D*(H-h));//对 L=D-x+H-D*(H-h)/x求导后,计算出的x的值。
left=D-D*h/H;
right=D;
if(right<x)x=right;//x在right的右侧
else if(x<left)x=left;//x在left的左侧。
L=D-x+H-D*(H-h)/x;
printf("%.3lf\n",L);
}
return 0;
}
#10017 「一本通 1.2 练习 4」传送带
//#10017. 「一本通 1.2 练习 4」传送带
//在线测评地址https://loj.ac/problem/10017
//P2571 [SCOI2010]传送带
//在线测评地址https://www.luogu.org/problemnew/show/P2571
//仔细读题,发现没什么感觉。
//AB与CD 位置关系,可能平行,内八字,外八字,交叉。
//此文思路讲得还可以https://blog.csdn.net/sadnohappy/article/details/52206450摘抄如下:
//这题我们先假设在AB线段确定了一个点(x,y),那么(x,y)到CD线段的一个点(x′,y′)的距离加上(x′,y′)
//到D点的时间显然是呈一个二次函数。于是我们可以在AB线段上枚举一个点,三分CD上的点,然后取最优即可。
//但是,这样可能会超时,我们考虑点A到(x,y)
//的时间随着距离增大而增大,这说明这里的函数是一条直线,那么显然(x,y)也可以三分出来。这样时间复杂度是O(log23L)(L是线段最长距离),所以是很快的。
//此文代码写得不错http://hzwer.com/4255.html
//三分套三分
//一开始,除错,r,q ,样例都无法通过。
//若不加fabs 洛谷中,测试点7,8WA。
//修改,提交AC。2018-10-15 19:30
#include <stdio.h>
#include <math.h>
#define eps 1e-6
double ax,ay,bx,by,cx,cy,dx,dy,p,q,r;
double dis(double x1,double y1,double x2,double y2){
return sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
}
double judge(double x,double y){
double lx,ly,rx,ry,xmid,xmmid,ymid,ymmid,t1,t2;
lx=cx,rx=dx,ly=cy,ry=dy;
while(fabs(rx-lx)>eps||fabs(ry-ly)>eps){//此处写成 while(lx+eps<rx||ly+eps<ry)
xmid=(lx+rx)/2,xmmid=(xmid+rx)/2;
ymid=(ly+ry)/2,ymmid=(ymid+ry)/2;
t1=dis(ax,ay,x,y)/p+dis(x,y,xmid,ymid)/r+dis(xmid,ymid,dx,dy)/q;//此处写成 t1=dis(ax,ay,x,y)/p+dis(x,y,xmid,ymid)/q+dis(xmid,ymid,dx,dy)/r;
t2=dis(ax,ay,x,y)/p+dis(x,y,xmmid,ymmid)/r+dis(xmmid,ymmid,dx,dy)/q;//此处写成 t2=dis(ax,ay,x,y)/p+dis(x,y,xmmid,ymmid)/q+dis(xmmid,ymmid,dx,dy)/r;
if(t1<t2)rx=xmmid,ry=ymmid;
else lx=xmid,ly=ymid;
}
return dis(ax,ay,x,y)/p+dis(x,y,lx,ly)/r+dis(lx,ly,dx,dy)/q;//此处写成 dis(ax,ay,x,y)/p+dis(x,y,lx,ly)/q+dis(lx,ly,dx,dy)/r;
}
int main(){
double lx,ly,rx,ry,xmid,xmmid,ymid,ymmid;
scanf("%lf%lf%lf%lf%lf%lf%lf%lf",&ax,&ay,&bx,&by,&cx,&cy,&dx,&dy);
scanf("%lf%lf%lf",&p,&q,&r);
lx=ax,rx=bx,ly=ay,ry=by;
while(fabs(rx-lx)>eps||fabs(ry-ly)>eps){//此处写成 while(lx+eps<rx||ly+eps<ry)
xmid=(lx+rx)/2,xmmid=(xmid+rx)/2;
ymid=(ly+ry)/2,ymmid=(ymid+ry)/2;
if(judge(xmid,ymid)<judge(xmmid,ymmid))
rx=xmmid,ry=ymmid;
else
lx=xmid,ly=ymid;
}
printf("%.2lf\n",judge(lx,ly));
return 0;
}
2018-10-15 19:36 AC该节内容。