二分法
二分查找又称折半查找,优点是比较次数少,查找速度快,平均性能好;其缺点是要求待查表为有序表,且插入删除困难。一般在单调函数中用得比较多,直接看题吧。
思路:
这里直接查找所求,也就是每个人能得到的最大pie,然后条件是right-left>1e-6,这种对精度要求比较高的大都可以这样写
代码:
#include<cstdio>
#include<cstring>
#include<math.h>
#include<iostream>
#include<iomanip>
#include<algorithm>
using namespace std;
#define pi acos(-1)
double r[10005];
int main()
{
int n,f,i,s,t,m;
double sum2,sum1,v,left,right,mid;
cin>>t;
while(t--)
{
cin>>n>>f;
sum1=0;
for(i=0;i<n;i++)
{
cin>>m;
r[i]=(double)m*m*pi;
sum1+=r[i];
}
v=1.0*sum1/(f+1);
left=0;
right=v;
while(right-left>0.000001)
{
mid=(left+right)/2.0;
s=0;
for(i=0;i<n;i++)
{
s+=(int)(r[i]/mid);
}
if(s>=f+1)
left=mid;
else
right=mid;
}
cout<<setiosflags(ios::fixed)<<setprecision(4)<<mid<<endl;
}
return 0;
}
思路:
这个题目就是很正常的二分,条件为left+1< right,但是这个题目又有点不同,它有三个序列,我之前是把第一二个排序然后暴力,第三个二分,结果爆时间了,后来发现题解是把第一第二个序列加起来排序,然后对这个新序列二分查找x-c[i]
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int t=0;
long long a[505],b[505],c[505];
long long sum[250005];
int main()
{
int l,m,n,i,j,left,mid,right,flag,s,k;
long long x,now;
while(cin>>l>>n>>m)
{
k=0;
for(i=0;i<l;i++)
cin>>a[i];
for(i=0;i<n;i++)
cin>>b[i];
for(i=0;i<m;i++)
cin>>c[i];
for(i=0;i<l;i++)
for(j=0;j<m;j++)
sum[k++]=a[i]+b[j];
sort(sum,sum+k);
cout<<"Case "<<++t<<":"<<endl;
cin>>s;
while(s--)
{
cin>>x;
flag=0;
for(i=0;i<m;i++)
{
left=0;
right=k-1;
now=x-c[i];
while(left+1<right&&!flag)
{
mid=(left+right)/2;
if(now>=sum[mid])
left=mid;
else
right=mid;
}
if(sum[left]==now||sum[right]==now)
flag=1;
if(flag)
break;
}
if(flag)
cout<<"YES"<<endl;
else
cout<<"NO"<<endl;
}
}
return 0;
}
思路:
这个题目跟第一题一样对精度要求很高,直接二分查找高度,条件是right-left>1e-7利用圆台体积公式v=mid*pi*(r*r+r*l+l*l)/3.0,像这种精度要求很高的就直接查找所求,不要转弯什么的,我朋友求的是半径,结果一下午都WA了
代码:
#include<cstdio>
#include<cstring>
#include<iomanip>
#include<math.h>
#include<iostream>
#include<algorithm>
using namespace std;
#define pi acos(-1)
int main()
{
int t;
cin>>t;
while(t--)
{
double r,R,H,V;
cin>>r>>R>>H>>V;
double left,right,mid,l,v;
left=0;
right=H;
while(right-left>1e-7)
{
mid=(right+left)/2.0;
l=mid*(R-r)/H+r;
v=mid*pi*(r*r+r*l+l*l)/3.0;
if(v<=V)
left=mid;
else
right=mid;
}
cout<<setiosflags(ios::fixed)<<setprecision(6)<<mid<<endl;
}
return 0;
}
思路:
这个题目我觉得好玄啊,我还是像之前那样用right-left>1e-6,结果不知道为什么他保留四位小数没有四省五入,输出6位是1.615150,保留4位就变成了1.6151,然后我就想着把他乘以100000然后手动判断要不要进位,结果乘以100000后就变成161514了。。。后面同学就帮我把条件改成fabs(a(mid)-y)>1.0e-6,输出6位还是1.615150,4位就变成1.6152了,这我就有点不懂了。。。
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<iomanip>
#include <cmath>
using namespace std;
double a(double x)
{
return 8*x*x*x*x + 7*x*x*x + 2*x*x + 3*x + 6;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
double y;
scanf("%lf",&y);
if(y<a(0)||y>a(100))
{
printf("No solution!\n");
continue;
}
double l,r,mid;
l=0;
r=100;
mid=(r+l)/2;
while(fabs(a(mid)-y)>1.0e-6)
{
mid=(r+l)/2.0;
if(a(mid)>y)
r=mid;
else
l=mid;
}
printf("%.4lf\n",mid);
}
return 0;
}