链接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=27642#overview
这一次是二分、三分全场.............也是本人我第一次做这类的题目.......虽然如此但感觉还不错.....
这次的组队赛名次与上次持平,但AC个数与第一名相同,只是时间多了......总体来说有进步~嗯~队友给力啊~~
A.POJ 1905 Expanding Rods
给出了弧长L和弧长两端的直线l距离,求弧长和直线的最大距离~
采用二分求圆的半径,在l/2和一个代入式子中能使L'小于所给的L的半径之间二分求取合适的半径r(L'=r*2*arcsin(l/(2*r))),再用式子r-sqrt(r^2-l^2/4)求H的长度。
代码如下(队友):
1 #include<iostream> 2 #include<stdio.h> 3 #include<algorithm> 4 #include<math.h> 5 using namespace std; 6 double l; 7 double f(double a) 8 { 9 return 2*asin(l/(a*2))*a; 10 } 11 double g(double b) 12 { 13 return b-sqrt(b*b-l*l/4); 14 } 15 int main() 16 { 17 double n,c,r1,r2,L,mid; 18 while(scanf("%lf%lf%lf",&l,&n,&c)!=EOF) 19 { 20 if(l<0&&n<0&&c<0) 21 break; 22 if(l==0||n==0||c==0) 23 {printf("0.000\n");continue;} 24 r1=l/2; 25 r2=l; 26 L=(1+n*c)*l; 27 while(f(r2)>L) 28 r2=r2*2; 29 while(fabs(f(r1)-f(r2))>1e-9) 30 { 31 mid=r1/2+r2/2; 32 if(f(mid)>L) 33 r1=mid; 34 else if(f(mid)<L) 35 r2=mid; 36 else 37 break; 38 } 39 printf("%.3lf\n",g(mid)); 40 } 41 return 0; 42 }
B.POJ 2002 Squares
链接: Squares
C.POJ 2456 Aggressive cows
这题是我做的,磨了很久啊..........刚开始没有思路,后来有思路了,又在怎么使二分长度的时候跳出卡了很久,还WA了一次..........= =
思路:
因为是求最大的最小距离(最大是指要把牛完全放进仓库里使牛相互之间的距离尽可能的最大)(最小是指:在这些相互之间的距离中最小的是多少),显然,距离绝不会超过最大仓库与最小仓库之间的距离L。所以用二分法求最大的最小距离,在0~L之间二分。
代码如下:
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 using namespace std; 5 6 int N,C,a[1000000]; 7 8 int juge(int m) //判断该长度是比所求长度大了还是小了 9 { 10 int number=1,i,frontt=0; 11 for(i=0;i<N;i++) 12 { 13 if((a[i]-a[frontt])>=m) 14 { 15 frontt=i; 16 number++; 17 if(number==C) return 1; //能把牛全部放进仓库,该长度m<=所求长度 18 } 19 } 20 return 0; //不能把牛全部放进仓库,该长度m>所求长度 21 } 22 23 int main() 24 { 25 int i,midd,left,right; 26 scanf("%d%d",&N,&C); 27 for(i=0;i<N;i++) 28 scanf("%d",&a[i]); 29 sort(a,a+N); 30 left=0; 31 right=a[N-1]-a[0]; 32 while(left<=right) //这一段的循环是重点!!!因为一定会有一个整数输出,不存在精度的问题,跳出就无法用精度判断!!!而是使用左右点判断!!! 33 { 34 midd=(left+right)/2; 35 if(juge(midd)) 36 left=midd+1; //+1和-1是为了使left>right的情况存在,使循环结束;若没有+1和-1则无法使循环结束。 37 else 38 right=midd-1; 39 } 40 printf("%d\n",right); //循环结束时,正好left比所求点大1,right就为所求点 41 return 0; 42 }
D.HDU 2141 Can you find it?
同样采用二分,不过有三组数,因此先合并两组做一组数hebin[],在和另一组c[]一起处理.hebin[]=x[i]-c[],二分hebin[]组,看是否能在hebin[]找出符合式子的值。
代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 7 int a[510],b[510],c[510],hebin[250010],x[1010]; 8 int A,B,C,X; 9 10 int juge(int key) //判断在hebin[]是否有符合式子的值~ 11 { 12 int left,right,midd,i; 13 left=0; 14 right=A*B-1; 15 while(left<=right) 16 { 17 midd=(left+right)/2; 18 if(hebin[midd]<=key) 19 left=midd+1; 20 else 21 right=midd-1; 22 } 23 if(right<0 || right>A*B-1) return 0; //注:有可能该值其实超出了hebin[]的范围,那么right有可能会为-1,因此单独返回0; 24 if(hebin[right]==key) return 1; 25 else return 0; 26 } 27 28 int main() 29 { 30 int ii=0; 31 while(scanf("%d%d%d",&A,&B,&C)!=EOF) 32 { 33 ii++; 34 int i,j,h,p; 35 for(i=0;i<A;i++) 36 scanf("%d",&a[i]); 37 for(i=0;i<B;i++) 38 scanf("%d",&b[i]); 39 for(i=0;i<C;i++) 40 scanf("%d",&c[i]); 41 scanf("%d",&X); 42 for(i=0;i<X;i++) 43 scanf("%d",&x[i]); 44 printf("Case %d:\n",ii); 45 for(i=0,h=0;i<A;i++) //我是把前两组进行合并~ 46 for(j=0;j<B;j++) 47 hebin[h++]=a[i]+b[j]; 48 sort(hebin,hebin+A*B); 49 for(i=0;i<X;i++) 50 { 51 p=0; 52 for(j=0;j<C;j++) 53 if(juge(x[i]-c[j])){p=1; break;} 54 if(p==1) printf("YES\n"); //p=1表示至少有一种方式能凑出xi 55 else printf("NO\n"); 56 } 57 58 } 59 return 0; 60 }
E.HDU 2199 Can you solve this equation?
我想这是最简单和最基础的二分了吧~
代码:
1 #include<stdio.h> 2 #include<math.h> 3 int main() 4 { 5 int y,T; 6 scanf("%d",&T); 7 while(T--) 8 { 9 double l=0,r=100,mid,sum; 10 scanf("%d",&y); 11 if(y<6||y>807020306) 12 { 13 printf("No solution!\n"); 14 continue; 15 } 16 while(r-l>1e-9) 17 { 18 mid=(r+l)/2; 19 sum=pow(mid,4)*8+7*pow(mid,3)+mid*mid*2+3*mid+6; 20 if(sum>y) 21 r=mid; 22 else if(sum<y) 23 l=mid; 24 else if(sum==y) 25 break; 26 } 27 printf("%.4lf\n",mid); 28 } 29 return 0; 30 }
(小夕的代码.......然后呢~嘻嘻~是我改正的........错在了让人很无语的地方......= =)
F.HDU 2899 Strange fuction
用三分的方法,小夕童鞋用了二分(求导,然后所求极值点即所求的x值,代入F(x)中得到所求值)答案很接近但还是不对~
我想了一下觉得,用二分,是用F(x)的导函数求得的,因为本来求得的值就有很大误差,而这个误差是在导函数的范围内并不是原函数的,而题目所给的精度应该是满足原函数而不是导函数。因此把有误差的x代入原函数中,所求的值的误差会扩大!!!!因此用二分求得的值很接近应得值,但是绝不是应得值!!!
代码:
1 #include<iostream> 2 #include<stdio.h> 3 #include<algorithm> 4 #include<math.h> 5 using namespace std; 6 double y; 7 double dis(double x) 8 { 9 return 6*pow(x,7)+8*pow(x,6)+7*pow(x,3)+5*x*x-y*x; 10 } 11 int main() 12 { 13 double left,right,mid,mmid,t2,t1; 14 int t; 15 scanf("%d",&t); 16 while(t--) 17 { 18 mid=1;mmid=0; 19 scanf("%lf",&y); 20 left=0;right=100; 21 while(fabs(mid-mmid)>1e-9) 22 { 23 mid=left/2+right/2; 24 mmid=mid/2+right/2; 25 t2=dis(mid);t1=dis(mmid); 26 if(t2>t1) 27 { 28 left=mid; 29 } 30 else if(t2<t1) 31 { 32 right=mmid; 33 } 34 else 35 break; 36 } 37 printf("%.4lf\n",t1); 38 } 39 return 0; 40 }
G.HDU 2298 Toxophily
我采用的是数学方法做的,代码很短~~链接:Toxophily
H.HDU 4355 Party All the Time
三分~
代码:
1 #include<stdio.h> 2 #include<string.h> 3 #include<stdlib.h> 4 double ab(double x) 5 { 6 return x>0?x:-x; 7 } 8 struct node 9 { 10 double x; 11 double w; 12 }q[50005]; 13 int n; 14 double cal(double xi) 15 { 16 int i; 17 double res=0; 18 for(i=0;i<n;i++) 19 { 20 double t=ab(q[i].x-xi); 21 res+=t*t*t*q[i].w; 22 } 23 return res; 24 } 25 int main() 26 { 27 int ca=1,i,t; 28 double l,r,m,mm,ans; 29 scanf("%d",&t); 30 while(t--) 31 { 32 scanf("%d",&n); 33 for(i=0;i<n;i++) 34 scanf("%lf%lf",&q[i].x,&q[i].w); 35 l=q[0].x; 36 r=q[n-1].x; 37 while(l<r) 38 { 39 if(ab(r-l)<=0.001) 40 break; 41 m=(l+r)/2; 42 mm=(m+r)/2; 43 if(cal(m)<cal(mm)) 44 { 45 ans=cal(m); 46 r=mm; 47 } 48 else l=m; 49 } 50 printf("Case #%d: ",ca++); 51 printf("%.0lf\n",ans); 52 } 53 return 0; 54 }