理論: 二分查找(2): 假定一個解並判斷是否可行

例題

有N條繩子, 他們的長度分別爲Li。 如果他們中切割出k條長度相同的繩子的話, 這K條繩子每條最長能有多長? 答案精確到小數點後兩位。

二分查找分析

這個問題用二分查找可以非常容易的求得答。 然我們套用二分搜索的模型試着解答這個問題。

令:

 條件C(x):= 可以得到K條程度爲X的繩子

則問題就變成了滿足c(x)條件的最大x的問題。 在初始化區間的時候, 只需要使用充分大的數INF作爲上界即可。(設置一個無窮大INF 遠比統計數列的最大值省時間)

const int INF = Oxfffffff;

int l = 0
int u = INF

現在的問題是如何搞笑的判斷c(x)是否可行。 由於長度爲Li的繩子最多可以切出floor(Li / x)段長度的繩子, 因此

C(x) = (floor(l / x)的總和是否大於或等於K

這道題可以在0(N)的時間中判斷出來。

代碼

int n, k;
double a[100000000];

bool check(double t)
{
    int num = 0;
    for (int i = 0; i < n; i++)
        num += (int)(a[i] / t);
    return num >= t;
}

double find(void)
{
    double l = 0, u = INF;
    for (int i = 1; i <= 100; i++)
    {
        double mid = (l + u) / 2;
        if (check(mid))
            l = mid;
        else
            u = mid;
    }
    return u;
}

int main(void)
{
    while (scanf("%d %d", &n, &k) != EOF)
    {
        for (int i = 0; i < n; i++)
            scanf("%lf", &a[i]);
        double ans = find();
        printf("%.2lf\n", ans);
    }
    return 0;
}

就像上文在求解最大化或者最小化的過程中, 能偶比較簡單的判斷條件是否滿足, 那麼就使用二分查找法就可以很好的解決問題。

有關結束的判定

在輸出小數的問題中一般都會指定允許的無法範圍, 或者輸出指定範圍中的小數點後面的位數。因此在二分搜索法的時候, 有必要設置合理的結束條件來滿足精度的要求。 在上述的程序中, 我們指定了循環次數作爲終止條件。 一次循環可以把區間的範圍縮小一半, 100次的循環則可以達到 1e-30 的精度, 基本上是沒有問題的。 除此之外 , 也可以把終止條件設爲像(u - l) > EPS 這樣, 指定一個區間大小, 在這種情況下, 如果EPS過小, 就有可能應爲浮點數小數精度的原因導致死循環, 千萬小心。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章