ACwing算法基礎課聽課筆記(第一章,基礎算法一)(二分)


  二分法:

    在看這個視頻前,我對於二分法是一頭霧水的,又加上這個算法我個人很容易寫錯emm...。視頻提到ACwing上的一道題,我用自以為聰明的方法去做,結果TLE了,實在丟人,不說了,開整!

    對於例題 789:數的范圍,尋找一個數前后第一次與最后一次出現的坐標。我們需要這個模板:

    

    數組定為number[];

    (1)來看第一種情況:如圖,假設兩個點分別是最先與最后出現的位置。求第一次x出現的位置實際上就是(1)這種情況。那么我們定一個條件

    mid=(l+r)>>1  if(number[mid]在a中)  

              r=mid;  區間變為[L,mid], 因為mid處可能是答案,所以mid不要加一也不要減一。

             else(落在b中)  

                  l=mid+1;   區間變為[mid+1,R]  

    (2)來看第二種情況:如圖,就是求x最后一次出現的位置了。依然是

   int mid=(l+r+1)>>1;    if(number[mid]在b中)  

                l=mid    區間變為[mid,R],mid不要動因為mid處可能是答案

             else    

                r=mid-1  因為mid處肯定不是答案,所以要減一,區間變為[L,mid-1];

    但是注意要注意(2)中的(L+r+1)>>1,因為如果  l=r-1時,式子不加一會出現mid=L+1/2,因為向下取整,所以mid=L,進入if后會一直求出區間[L,R]造成死循環,而(1)就不會出現。

    綜上,有以下兩個模板,分別對應不同的情況

//區間[L,R]被分成[L,mid]和[mid+1,R]時
int
bsearch_1(int l,int r) { while(l<r) { int mid=l+r >>1; if(check(mid)) r=mid; else l=mid+1; } }
//區間[L,R]被分成[L,mid-1]和[mid,R]時
int bsearch_2(int l,int r) 
{
  while(l<r)
  {
    int mid=l+r+1 >>1;
    if(check(mid))
      l
=mid;
   
else
      r
=mid-1; }
 }

 

   然后上789代碼  :  

#include<iostream>
const int maxn=1e5+10;
using namespace std;

int a[maxn];
int n,k;
int main()
{
    cin>>n>>k;
    for(int i=0;i<n;i++)
        cin>>a[i];
    while(k--)
    {
        int x;
        cin>>x;
        int l=0,r=n-1;
        while(l<r)
        {
            int mid=(l+r)>>1;
            if(a[mid]>=x)
            {
                r=mid;
            }
            else
            {
                l=mid+1;
            }
        }
        if(a[l]!=x)
            cout<<"-1 -1"<<endl;
        else
        {
            cout<<l<<' ';
            int l=0,r=n-1;
            while(l<r)
            {
                int mid=(l+r+1)>>1;
                if(a[mid]<=x)
                {
                    l=mid;
                }
                else
                    r=mid-1;
            }
            cout<<r<<endl;
        }
    }
}

    再來個手動開方嘿嘿,二分法:

    

#include<iostream>
using namespace std;
#include<cstdio>
int main()
{
    double x;
    while(cin>>x)
    {
        double l=0,r=x;
        while((r-l)>1e-6)//精度不夠再加,可以時1e-8
        {
            double mid=(l+r)/2;
            if(mid*mid>x)
                r=mid;
            else
                l=mid;
        }
        printf("%lf\n",l);
    }
}

  

  開三次方:ACWING  790

  

#include<iostream>
#include<cmath>
#include<cstdio>
using namespace std;
int main()
{
    double x;
    while(cin>>x)
    {
        double l,r;
        if(x>=0)
            l=0,r=x;
        else
            l=x,r=0;
        while(fabs(r-l)>1e-8)
        {
            double mid = (l+r)/2;
            if(mid*mid*mid>x)
                r=mid;
            else
                l=mid;
        }
        printf("%lf\n",l);
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM