二分法

吃可爱长大的小学妹 提交于 2020-03-06 21:48:14

Date:2019-07-25 16:03:14

算法实现

  1 /*---------------------------有序数组中查找给定数字x-------------------------*/
  2 #include <stdio.h>
  3 
  4 //left=0, right=n-1
  5 int binarySearch(int A[], int left, int right, int x)
  6 {
  7     int mid;    //mid为left和right的中点
  8     while(left <= right)
  9     {
 10         //
 11         // 若right超过int型上界的一半,则left+right可能溢出
 12         // mid = left + (right - left)/2; 替代
 13         //
 14         mid = (left+right) / 2;
 15 
 16         if(A[mid] == x)
 17         {
 18             return mid;
 19         }
 20         else if(A[mid] > x)        //中间数大于x,则往左区间查找
 21         {
 22             right = mid - 1;
 23         }
 24         else                    //中间数小于x,则往右区间查找
 25         {
 26             left = mid + 1;
 27         }
 28     }
 29 
 30     return -1;    //查找失败,返回-1
 31 }
 32 
 33 int main(void)
 34 {
 35     const int n = 10;
 36     int A[n] = {1, 3, 4, 6, 7, 8, 10, 11, 12, 15};
 37     printf("%d %d\n", binarySearch(A,0,n-1,6), binarySearch(A,0,n-1,9));
 38     /*
 39     output:
 40         3 -1
 41     */
 42 
 43     return 0;
 44 }
 45 
 46 /*----------------------求序列中的第一个大于等于x的元素的位置-------------------*/
 47 
 48 //left=0, right=n
 49 int lower_bound(int A[], int left, int right, int x)
 50 {
 51     int mid;
 52     while(left < right)        //当left==right时,找到该位置
 53     {
 54         mid = left + (right-left)/2;
 55         if(A[mid] >= x)
 56         {
 57             right = mid;
 58         }
 59         else
 60         {
 61             left = mid + 1;
 62         }
 63     }
 64 
 65     //
 66     // 若所有元素均大于x,则返回left的值为0,即x应插入的位置是A[0]
 67     // 若所有元素均小于x,则返回left的值为n,即x应插入的位置是A[n]
 68     //
 69     return left;
 70 }
 71 
 72 /*---------------------求序列中第一个大于x的元素位置---------------------------*/
 73 
 74 //left=0, right=n
 75 int upper_bound(int A[], int left, int right, int x)
 76 {
 77     int mid;
 78     while(left < right)
 79     {
 80         mid = left + (right-left)/2;
 81         if(A[mid] <= x)
 82         {
 83             left = mid + 1;
 84         }
 85         else
 86         {
 87             right = mid;
 88         }
 89     }
 90 
 91     return left;
 92 }
 93 
 94 /*-------------------------------计算根号2的近似值-----------------------------*/
 95 const double eps = 1e-5;        //精度为10^-5
 96 
 97 double f(double x)
 98 {
 99     return x*x;
100 }
101 
102 double calSqrt()
103 {
104     double left=1, right=2, mid;
105     while(right - left > eps)
106     {
107         mid = left + (right-left)/2;
108         if(f(mid) > 2)
109         {
110             right = mid;
111         }
112         else
113         {
114             left = mid;
115         }
116     }
117 
118     return mid;
119 }
120 
121 /*--------------给定一个定义在[L,R]上的单调函数f(x),求方程f(x)=0的根-----------*/
122 const double eps = 1e-1;
123 
124 double f(double x)
125 {
126     return /*f(x)*/;
127 }
128 
129 double solve(double L, double R)
130 {
131     double left=L, right=R, mid;
132     while(right-left < eps)
133     {
134         if(f(mid) < 0)
135         {
136             left = mid;
137         }
138         else
139         {
140             right = mid;
141         }
142     }
143 
144     return mid;
145 }
146 
147 /*-----------------------------装水问题---------------------------*/
148 /*
149 问题描述:
150     有一个侧面看去是半圆的储水装置,该半圆的半径为R,要求往里面装入高度为h的水,使其
151 侧面看去的面积S1与半圆面积S2的比例恰好为r。现给定R和r,求高度h。
152 */
153 
154 #include <cstdio>
155 #include <cmath>
156 
157 const double PI = acos(-1.0);
158 const double eps = 1e-5;
159 
160 double f(double R, double h)
161 {
162     double alpha = 2*acos((R-h)/R);
163     double L = 2*sqrt(R*R-(R-h)*(R-h));
164     double S1 = alpha*R*R/2 - L*(R-h)/2;
165     double S2 = PI*R*R/2;
166 
167     return S1/S2;
168 }
169 
170 double solve(double R, double r)
171 {
172     double left=0, right=R, mid;
173     while(right - left > eps)
174     {
175         mid = left + (right-left)/2;
176         if(f(R, mid) < r)
177         {
178             left = mid;
179         }
180         else
181         {
182             right = mid;
183         }
184     }
185 
186     return mid;
187 }
188 
189 int main(void)
190 {
191     double R, r;
192     scanf("%lf%lf", &R, &r);
193 
194     printf("%.4f\n", solve(R, r));
195 
196     return 0;
197 }
198 
199 /*----------------------------木棒切割问题---------------------------*/
200 /*
201 问题描述:
202     给出N根木棒,长度均已知,现在希望通过切割它们来得到至少K段长度相等的木棒(长度必须是整数),
203 问这些长度相等的木棒最长能有多长
204 输入样例:
205     3 7
206     10 15 24
207 输出样例:
208     6
209 */
210 #include <stdio.h>
211 #include <algorithm>
212 
213 using namespace std;
214 
215 const int MAX_SIZE = 100010;
216 
217 int wood[MAX_SIZE];
218 
219 int number(int len, int n)
220 {
221     int ans=0;
222     for(int i=0; i<n; i++)
223     {
224         ans += wood[i]/len;
225     }
226 
227     return ans;
228 }
229 
230 int main(void)
231 {
232     int n, k;
233     scanf("%d%d", &n, &k);
234 
235     for(int i=0; i<n; i++)
236     {
237         scanf("%d", &wood[i]);
238     }
239 
240     sort(wood, wood+n);
241 
242     /*
243     随着每段木棒长度的增加,获得最大段数的木棒数递减
244     即所求最后一个段数大于等于k的点,对应的长度即为所求
245     即if(number(mid,n) >= k),这样的判定条件会出现死循环
246     可以转化为,求第一个长度小于k的点,即if(number(mid,n) > k)
247     */
248     int left=1, right=wood[n-1], mid;
249     while(left < right)
250     {
251         mid = left + (right-left)/2;
252         if(number(mid, n) > k)
253         {
254             left = mid + 1;
255         }
256         else
257         {
258             right = mid;
259         }
260 
261     }
262 
263     printf("%d\n", left);
264 
265     return 0;
266 }
267 
268 /*-------------------------------快速幂-------------------------------*/
269 /*
270 问题描述:
271     求a^b,采用循环for(i=0; i<b; i++){ans *= a;},时间复杂度为O(b)
272     当b = 10^8甚至更大时,时间效率很低
273     因此,可以采用二分法达到O(logb)的时间复杂度
274 
275     试求,a^b % m 的结果
276 */
277 
278 //
279 // 递归写法
280 //
281 typedef long long LL;
282 
283 LL binaryPow(LL a, LL b, LL m)
284 {
285     if(b == 0)
286     {
287         return 1;    //a^0 = 1
288     }
289 
290     // b%2==1 等价于 b&1,即进行位与操作,判断b的末位是否为1,执行速度较快
291     if(b%2 == 1)    //b为奇数
292     {
293         return a * binaryPow(a, b-1, m) % m;
294     }
295     else            //b为偶数
296     {
297         //此处若return binary()*binary;则时间复杂度会翻倍
298         LL mul = binaryPow(a, b/2, m);
299         return mul*mul%m;
300     }
301 }
302 
303 //
304 // 迭代写法
305 //
306 typedef long long LL;
307 
308 LL binaryPow(LL a, LL b, LL m)
309 {
310     LL ans=1;
311 
312     //b = 13 = 8 + 4 + 1 = 2^3 + 2^2 + 2^0
313     //b                  = (1 1 0 1)2;
314     while(b > 0)
315     {
316         if(b&1)    //b的二进制个位==1, ans累乘
317         {
318             ans *= a % m;
319         }
320 
321         a = a * a % m;
322         b >>= 1;    //将b的二进制右移1位,即b=b>>1或b=b/2;
323     }
324 
325     return ans%m;
326 }

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!