二分法&三分法

ural History Exam    二分

 1 #include <iostream>
 2 #include <cstdlib>
 3 using namespace std;
 4 
 5 //二分查找
 6 bool binarySearch(long a[], long x, int n){
 7     int left = 0,right = n-1;
 8     int middle;
 9     while (left <= right){
10         middle = (left+right)/2;
11         if (x == a[middle]) return 1;
12         if (x > a[middle]) left = middle + 1;
13         else right = middle - 1;
14     }
15     return 0;
16 }
17 
18 int cmp(const void *a, const void *b)  {  
19     return *(int *)a - *(int *)b;  
20 }  
21 
22 int main(){
23     int numprofessor;
24     scanf("%ld",&numprofessor);
25     
26     long yearProfessor[numprofessor];
27     for(int i=0;i<numprofessor;i++){
28         scanf("%ld",&yearProfessor[i]);
29     }
30     
31     qsort(yearProfessor,numprofessor,sizeof(long),cmp);
32     long numstudent;
33     scanf("%ld",&numstudent);
34     
35     long result=0;
36     
37     long yearstudent[numstudent];
38     for(int i=0;i<numstudent;i++){
39         scanf("%ld",&yearstudent[i]);
40         if( binarySearch(yearProfessor, yearstudent[i], numprofessor)){
41             result++;
42         }
43         
44     }
45     
46     cout<<result;
47         
48 } 

 

 

二分

ural Fibonacci Sequence

第一遍用递归写,结果在数据比较大时,超时了。题目要求1000ms,测试结果是1029ms,代码如下:

 1 #include <iostream>
 2 using namespace std;
 3 
 4 int i,j,fi,fj,n;
 5 int count=0,count1=0,count2=0;
 6 int finext;           // 表示fi下一个f(i+1)的值 
 7 
 8 int fib1(int j){      /*递归程序1:计算fj时用到的fi和finext的次数  */  
 9       if(j==i){ 
10             count1++;   //记录fi用到的次数 
11           return 1; 
12       }
13       if(j==i+1){
14             count2++;   //记录finext用到的次数 
15             return 1;
16       }  
17       return  fib1(j-1) + fib1(j-2);
18 }
19 
20 long fib3 (int n){
21     //* 迭代解法:这里算法复杂度显然为O(n) ,
22    // 这个解法目前来看是最好的解法,算法既不复杂,而且在时间复杂度和空间复杂度上都有保证  
23     if(n==i){
24         return fi;
25     }   
26     if(n==i+1){
27         return finext;
28     }
29     long long x = fi, y = finext;
30     for (int a= i; a<n-1; a++){
31          y = x + y;
32          x = y - x;
33     }
34     return y;
35 }
36  
37 int main(){
38     cin>>i>>fi>>j>>fj>>n;
39     if(j<i){
40         int temp=j,temp1=fj;
41         j=i;
42         fj=fi;
43         i=temp;
44         fi=temp1;
45     } 
46     int a=fib1(j);
47     finext=(fj-count1*fi)/count2;
48     cout<<fib3(n)<<endl;
49     
50 }

回想了一下最近学习的二分法,发现暴力枚举后得二分优化,貌似可以过,遂有下代码:

 1 #include <iostream>
 2 using namespace std;
 3 
 4 const long long NLAR = 2000000000;
 5 long long i,fi,j,fj,n;
 6 
 7 int main(){  
 8     cin >> i >> fi >> j >> fj >> n;
 9     if(j<i){     //保证j>i 
10         int temp=j,temp1=fj;
11         j=i;
12         fj=fi;
13         i=temp;
14         fi=temp1;
15     }
16     
17     // cal f[i+1]
18     
19     long long left=-NLAR, right=NLAR, mid;
20     long long ti=fi, tj=mid, t;
21     while (left+1<right){
22         mid = (left+right)/2;
23         ti=fi; tj=mid;
24         for (int k=i+2; k<=j; ++k){
25             t=ti+tj; 
26             ti=tj;
27              tj=t;
28             if(t>NLAR*2 ||t<-NLAR*2) break;
29         }
30         if(tj>=fj) right = mid;
31             else left=mid;
32     }
33 
34     ti=fi; tj=right;
35     if(n>i){
36         for(int k=i+2;k<=n;++k){
37             t=ti+tj; 
38             ti=tj; 
39             tj=t;  
40         }    
41         cout << tj << endl;
42     }
43     else {
44         for(int k=i-1; k>=n; ++k){
45             t=tj-ti; 
46             tj=ti; 
47             ti=t;
48         }
49         cout << ti << endl;
50     }
51 
52     return 0;
53 }

 

三分法主要求解单峰函数极值,

ural Bookshelf

本题目中要求的函数的图像(取H=6,h=1)为:可以看出这是一个单峰函数,可以运用三分法求极值。

 

 

 1 #include <iostream>
 2 #include <cstdlib>
 3 #include <iomanip> 
 4 #include <cmath>
 5 using namespace std;
 6 #define EPS 1e-9
 7 
 8 int h,H,L;
 9 double fx(double x){
10     return H/2.0*x/sqrt(h*h+x*x)-x;    
11 }
12 
13 int main(){
14     cin>>h>>H>>L;
15     double left=0,right=H;
16     long double isover=1;
17     
18     while(isover>EPS){
19         double m1=left+(right-left)/3;
20         double m2=right-(right-left)/3;
21         
22         double fm1=fx(m1);
23         double fm2=fx(m2);
24         
25         if(fm1<fm2) left=m1;
26         else  right=m2;
27         isover=right-left;
28     }
29     cout<<fixed<<setprecision(6)<<fx(right)<<endl; 
30 } 

 

 

这里再收录一个关于二分法的课堂例题,poj1064

 1 /*
 2  * poj-1064 Cable master.cpp
 3  *      二分, 化为整数存储,下界为1(cm),上界为最长绳的长度
 4  *
 5  */
 6 #include<cstdio>
 7 using namespace std;
 8 
 9 const double eps = 1e-7;    //注意精度
10 const int maxn = 10000 + 10;
11 
12 int n, k, cable[maxn];
13 
14 int main(){
15     scanf("%d%d", &n, &k);
16     double ftmp;
17     int tmpMax = 0;
18     for(int i=0; i<n; i++){
19         scanf("%lf", &ftmp);
20         cable[i] = int((ftmp+eps) * 100);    //精度
21 
22         if(cable[i] > tmpMax) tmpMax = cable[i];
23     }
24 
25     int up = tmpMax, low = 1, mid = -1, ans = -1;
26     int tmpNum = 0;
27     while(low <= up){
28         mid = (up + low) / 2;
29         tmpNum = 0;
30         for(int i=0; i<n; i++)
31             tmpNum += cable[i] / mid;
32 
33         if(tmpNum >= k){
34             if(mid > ans) ans = mid;
35             low = mid + 1;
36         }
37         else
38             up = mid - 1;
39     }
40 
41     if(ans < 1)
42         printf("0.00\n");
43     else
44         printf("%.2lf\n", ans * 0.01);
45 
46 
47     return 0;
48 }
poj1064

 

posted on 2015-10-18 15:55  逸阳  阅读(558)  评论(0编辑  收藏  举报

导航