理论: 二分查找(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过小, 就有可能应为浮点数小数精度的原因导致死循环, 千万小心。

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