二分查詢也稱折半查詢(binary search),它是一種效率非常高效的查詢方法。每次拿目標數值(以下用value表示)與陣列中間位置的資料(以下用arry[mid]表示,mid表示陣列中間位置索引值)進行比較,如果value大於arry[mid],繼續將value與大於arry[mid]部分的中間位置的值進行比較;如果value小於arry[mid],繼續將value與小於arry[mid]部分的中間位置值進行比較。
1. 排序
二分查詢的前置條件便是「有序」,因為如果無序便無「左右邊界」,(網線這個題可以不用事先排序,因為我們是順著長短的順序來尋找最優的解,網線這個題後邊會解釋)所以在執行二分之前可以先用冒泡或者sort函式排序,排序從小到大或從大到小均可。
#include
//sort函式的標頭檔案
bool
cmp(
int x,
int y)
sort
(a, a+n, cmp)
;
2. 標序號
一般查詢陣列裡邊的元素,陣列的下標就是序號。標序號主要是為了方便找尋左右邊界,但是有的題比較靈活,例如網線這個題,網線的長度可以直接作為左右邊界,這樣的話,「序號」就是網線長度本身。
3. 找迴圈終止條件,找左右邊界
這裡就有玄學了,之前沒能深入理解,導致二分存在瑕疵。
迴圈終止條件
while
(r>=l)
/*這種條件在最後(沒能找到一直在找)左邊界會大於右邊界,
在處理邊界的時候容易出問題。*/
while
(r-l>1)
/*這種在最後左邊界依舊小於右邊界,在處理細節方面,
這種更方便,所以演算法書上是這種。。。*/
左右邊界
int a[10]
=;int l=
0, r=9;
//這個邊界對應的是上邊第一種終止條件。
int l=-1
, r=10;
/*這個邊界對應的是上邊第二種終止條件。為了
防止邊界被「打破」,所以這裡的左右邊界都要超出一點*/
4. 求 mid (中間值)
在沒有深入了解之前,我的mid是這樣的:
mid =
(l+r)/2
;
但是這有個弊端,這樣找mid值容易越界,所以有了這種:
mid = l +
(r-l)/2
;mid = l +
(r-l)
>>
1;
5. 比較判斷
大致思想已經了解了,這裡我只說細節。
大致有這麼倆種模板
l = mid +1;
r = mid -1;
l = mid;
r = mid;
在這裡我把倆種模板彙總一下:
int a[10]
=;int l =
0, r =
9, key, mid;
scanf
("%d"
,&key)
;//key是要查詢的值。
while
(r>=l)
printf
("%d"
, mid)
;
int a[10]
=;int l =-1
, r =
10, mid, key;
cin >> key;
while
(r - l >1)
printf
("%d"
, mid)
;
當然,簡單的陣列查詢值是看不出來倆者的差別的,現在上題!
網線切割:
題目描述:
wonderland居民決定舉行一屆地區性程式設計大賽。仲裁委員會志願負責這次賽事並且保證會組織一次有史以來最公正的比賽。為此,所有參賽者的電腦和網路中心會以星狀網路連線,也就是說,對每個參賽者,組委會會用一根長度一定的網線將他的計算機與中心連線,使得他們到網路中心的距離相等。
為了買網線,組委會與當地的網路公司聯絡,要向他們購買一定數目的等長網線,這些網線要盡可能的長,使得組織者可以讓選手們彼此遠離。
於是公司指派管理網線事務的負責人解決此事。負責人清楚地知道倉庫裡每根網線的長度(精確到厘公尺:cm),他也可以將他們以厘公尺的精度切割——前提是他得知道切成多長。但是現在,這個長度他算不出來,於是他徹底迷茫了。
你要做的,就是幫助困惑的負責人。編乙個程式求出為了得到一定數目的等長網線,每根網線最大的可能長度。
輸入:輸入檔案的第一行由兩個整數n和k組成,由乙個空格間隔。n(1≤n≤10000)是倉庫裡光纜的數目,k(1≤k≤10000)是需要的網線數目。
接下來的n行每行只有乙個實數,告訴你每根纜線的長度(單位:m)。這些網線至少長1m,最多不超過100km。 所有的長度精確到cm,且小數點後有且僅有兩位。
輸出:把你求得的最大網線長度寫進輸出檔案(單位:m)。長度要精確到cm,並且輸出時小數點後要恰有兩位。
如果無論如何也不可能切割出需要數目的網線(每根至少1cm長),那麼就輸出「0.00」(不包括引號)。
樣例輸入:
4 11
8.02
7.43
4.57
5.39
樣例輸出:
2.00
我在這裡給出倆版能ac的**:
#include
using
namespace std;
double line[
10000+10
];int n, k;
int l, r, mid;
intmain()
l =0;
r++;//這裡左右邊界都超出原本範圍一點點。
int sum;
while
(r - l >1)
if(sum >= k) l = mid;
else r = mid;
}double ans = l;
//這裡用左界為答案。
ans = ans *
1.0/
100;
printf
("%.2lf"
, ans)
;return0;
}
#include
using
namespace std;
double line[
10000+10
];int n, k;
int l, r, mid;
intmain()
l =1;
int sum;
while
(r>=l)
if(sum >= k) l = mid +1;
else r = mid -1;
}double ans = r;
//這裡則用右界為答案,因為這個判斷條件,此時右界小於左界。
ans = ans *
1.0/
100;
printf
("%.2lf"
, ans)
;return0;
}
繩子切割 二分查詢
題目描述 有n條繩子,它們的長度為li li 1000 如果從它們中切割出k條長度相同的繩子的話,這條繩子每條最長能有多長?答案保留到小數點後2位。輸入輸入包含兩行,第一行有兩個整數n和k,n代表n條繩子,k代表切割出的長度。4 11 8 02 7.43 4.57 5.39 輸出輸出能切割出最長的長...
二分查詢 切割問題
工地現有 n 根鋼管,第 i 根鋼管的長度為 a i 現在想用這 n 根鋼管來做乙個支撐用的柱子。我麼可以切割這些鋼管成為更短的鋼管,但是不能縫合兩根鋼管。為了安全起見,柱子必須用 至少 k 根長度相同的鋼管加上混凝土製成,並且要求鋼管長度必須為 整數。這個柱子最高能建成多高 鋼管可以有剩餘 輸入格...
二分 木棒切割
問題 給出n根木棒,長度均已知,現在希望通過切割他們來得到至少k段長度相等的木棒 長度必須為整數 問這些長度相等的木棒最長有多長?這一題可以利用二分的思想來求解,最短是0 left 最長為最長木棒的長度 right 不斷對這個區間進行二分,且每次分完計算所能得到的木棒的條數,如果相同則返回,否則繼續...