序:
二分搜尋是很常見的一種演算法,用來在有序序列中尋找某數(或者小於大於它的最*值的某數)。
二分答案也比較常見,估算出答案範圍後二分縮小範圍逼近答案。
二分推進與二分答案很像,不同之處是二分推進並非得到答案的範圍,而是通過縮小答案對應的資料的範圍,逼近答案對應的資料(通常求最值)…
舉個例子:
平面上有n個點,已知每個點的座標。求乙個點m(x,y),使得m與其他所有點的距離和最短。(x,y的精度為0.1,最終的距離和 < 最小值+0.01即可)
思路一:暴力列舉。
由於精度是0.1,所以我們可以從minx -> maxx, miny -> maxy列舉與所有點的距離,取最小。複雜度o(100n^2),n大一點即使忽略常數100(1/0.1*1/0.1)也得tle。
思路二:二分推進。
盡然我們想到了列舉,而且我們知道最小值的座標是唯一的。(不知道怎麼證,憑直覺這應該是顯然的…)
既然如此,假設這個點是m(x,y),對於m周邊的所有點一定距離和都要大於它的距離和(否則就不是最小了)。
還有乙個隱含條件:minx<=x<=maxx; miny<=y<=maxy;
最重要的一點,越接近m的點的距離和應該越接近最小值(答案)。
知道範圍,又知道答案的特殊性與資料範圍的單調性,那麼就可以使用二分推進演算法逼近了。
思路是這樣的:
1.選取範圍內的任意乙個點。
2.計算它的距離和以及它上下左右±r,也就是(x+r,y),(x,y+r)…四個座標的距離和,如果出現ans < minn,則相當於出現更優解,意味著答案應該更靠近那個點,所以我們將當前點更新為那個點繼續操作。
3.可能會出現上下左右4個點都比現在座標大,那看來是幅度太大了,r = r/2重複上一步操作。
偽**是這樣的:
while(步長大於誤差)}}
縮小步長
}
最終的座標就是答案。
**實現:
/*
about: t1 二分推進
auther: kongse_qi
date:2017/04/29
*/#include
#include
#include
#define maxn 10005
#define inf 0x7fffff
#define eps 0.01
using
namespace
std;
int n, a[maxn][2];
double maxx, maxy, minx, miny;
double ans[2], cur_ans = inf;
void read()
return ;
}double cal(double x, double y)
return ans;
}void solve()
, dicy = ;
double ne_ans;
cur_ans = cal(curx, cury);
while(r >= eps)}}
r *= 0.5;
}ans[0] = curx;
ans[1] = cury;
return ;
}int main()
這與啟發式搜尋很像,但是還沒有搞懂怎個啟發式。作為與二分答案法的姊妹演算法,暴力**後也可以看看能否通過二分優化。
至此結束。
箜瑟_qi 2017.04.29 23:49
二分推進演算法
序 二分搜尋是很常見的一種演算法,用來在有序序列中尋找某數 或者小於大於它的最 值的某數 二分答案也比較常見,估算出答案範圍後二分縮小範圍逼近答案。二分推進與二分答案很像,不同之處是二分推進並非得到答案的範圍,而是通過縮小答案對應的資料的範圍,逼近答案對應的資料 通常求最值 舉個例子 平面上有n個點...
演算法基礎 二分查詢函式 二分演算法
一 寫乙個函式binaryseach,在包含size個元素的 從小到大排序的int數a裡查詢元素p,如果找到,則返回元素下標,如果找不到,則返回 1。要求複雜度o log n int binarysearch int a,int size,int p return 1 複雜度o log n 二 寫乙...
演算法 二分查詢演算法
思想 二分搜尋主要解決的問題是確定排序後的陣列x 0,n 1 中是否包含目標元素target。二分搜尋通過持續跟蹤陣列中包含元素target的範圍 如果target存在陣列中的話 來解決問題。一開始,這個範圍是整個陣列,然後通過將target與陣列中的中間項進行比較並拋棄一半的範圍來縮小範圍。該過程...