zoukankan      html  css  js  c++  java
  • 二分算法的应用——不只是查找值!

    • 二分查找

    二分搜索法,不仅仅是查找值,在算法竞赛中,经常可以见到二分搜索法和其他算法结合的题目。

    • 从有序数组中查找某个值
    • 假定一个解并判断是否可行
    • 最大化最小值
    • 最大化平均值

    查找值(手写二分 和 使用lower_bound )

    #include <iostream>
    #include <algorithm>
    using namespace std;
    ​
    const int maxn = 1000 + 10;
    ​
    void solve()
    {
        int a[] = {1, 3, 8, 11, 14, 19, 20, 23, 39};
        int n = 9, k = 14;
        int lb = 0, ub = n;
    ​
        //重复循环, 直到解的存在范围不大于1
        while (ub - lb > 0)
        {
            int mid = (lb + ub) / 2;
            if (a[mid] > k) 
            {
                ub = mid;
            }
            else if (a[mid] < k)
            {
                lb = mid;
            }
            else
            {
                cout << mid << endl;
                break;
            }
        } 
    }
    ​
    void stl_solve()
    {
        int a[] = { 1, 3, 8, 11, 14, 19, 20, 23, 39 };
      
        int loc = lower_bound(a, a + 9, 14) - a;
        cout << loc << endl;
    }
    ​
    int main()
    {
    ​
        solve();
        stl_solve();
        return 0;
    }
    • 假定一个解并判断是否可行

    原题链接: http://poj.org/problem?id=1064

    题意: 有 N条绳子, 他们 长度分别为 。如果从它们中切割出  条长度相同 的绳子的话,这  条绳子每条绳子 最长能有多长? 答案保留到小数点后2 位。

    限制条件

    输入

    N = 4
    K = 11
    L = {8.02, 7.43, 4.57, 5.39}

    输出

    2.00 (每条绳子分别可以得到4条、3条、2条、2条,共计11条绳子)

    #include <iostream>
    #include <algorithm>
    #include <cstdio>
    using namespace std;
    ​
    /*
    4
    11
    8.02
    7.43
    4.57
    5.39
    */
    const int maxn = 10000 + 200;
    //输入
    int N, K;
    double L[maxn];
    double INF;
    ​
    //判断是否满足条件
    bool C(double x)
    {
        int num = 0;
        for (int i = 0; i < N; i++)
        {
            num += (int)(L[i] / x);        //求每条绳子按照x长度切出来的绳子数量 是否大于等于 K
        }
        return num >= K;
    }
    ​
    void solve()
    {
        //初始化解的范围
        double lb = 0, ub = INF;           // INF > MAX_L
    //重复循环,直到解的范围足够小
        for (int i = 0; i < 100; i++)
        {
            double mid = (lb + ub) / 2;
            if (C(mid)) {
                lb = mid;                  //将x的最小边界 设置为 mid
            }
            else {
                ub = mid;               
            }
        }
    ​
        printf("%.2f
    ",  floor(ub * 100) / 100);     //保留两位小数
    }
    ​
    void input()
    {
        cin >> N >> K;
        for (int i = 0; i < N; i++)
        {
            cin >> L[i];
            if (INF < L[i]) {
                INF = L[i];        //求出x最大可能值的右边界
            }
        }
        ++INF;
    }
    ​
    int main()
    {
        input();
        solve();
        return 0;
    }

    套用模板,求解蓝桥杯原题

    2017第八届蓝桥杯省赛第九题:分巧克力
    
     
    标题: 分巧克力
    ​
        儿童节那天有K位小朋友到小明家做客。小明拿出了珍藏的巧克力招待小朋友们。
        小明一共有N块巧克力,其中第i块是Hi x Wi的方格组成的长方形。
    ​
        为了公平起见,小明需要从这 N 块巧克力中切出K块巧克力分给小朋友们。切出的巧克力需要满足:
    ​
        1. 形状是正方形,边长是整数  
        2. 大小相同  
    ​
    例如一块6x5的巧克力可以切出6块2x2的巧克力或者2块3x3的巧克力。
    ​
    当然小朋友们都希望得到的巧克力尽可能大,你能帮小Hi计算出最大的边长是多少么?
    ​
    输入
    第一行包含两个整数N和K。(1 <= N, K <= 100000)  
    以下N行每行包含两个整数Hi和Wi。(1 <= Hi, Wi <= 100000) 
    输入保证每位小朋友至少能获得一块1x1的巧克力。   
    ​
    输出
    输出切出的正方形巧克力最大可能的边长。
    ​
    样例输入:
    2 10  
    6 5  
    5 6  
    ​
    样例输出:
    2
    ​
    资源约定:
    峰值内存消耗(含虚拟机) < 256M
    CPU消耗  < 1000ms

    #include <iostream>
    #include <algorithm>
    #include <cstdio>
    using namespace std;
    ​
    /*
    2 10  
    6 5  
    5 6  
    */
    const int maxn = 100000 + 20;
    int N, K;
    int INF;
    struct Eat {
        int Hi,
            Wi;
        Eat(int h = 0, int w = 0) : Hi(h), Wi(w) {}
    } Fs[maxn];
    ​
    bool C(int x)
    {
        int num = 0;
        for (int i = 0; i < N; i++)
        {
            num += ((Fs[i].Hi / x) * (Fs[i].Wi / x));
            if (num >= K) {
                return true;
            }
        }
        return false;
    }
    ​
    void solve()
    {
        //初始化解的范围
        int lb = 0, ub = INF;
        
        //重复循环, 直到解的范围足够小
        for (int i = 0; i < 100; i++)
        {
            int mid = (lb + ub) / 2;
            if (C(mid)) {
                lb = mid ;
            }
            else {
                ub = mid;
            }
        }
        cout << lb << endl;
    }
    ​
    void input()
    {
        int tmp = 0;
        cin >> N >> K;
        for (int i = 0; i < N; i++)
        {
            cin >> Fs[i].Hi >> Fs[i].Wi;
            tmp = max(Fs[i].Hi, Fs[i].Wi);
            if (INF < tmp) {
                INF = tmp;
            }
        }
        INF++;
    }
    ​
    int main()
    {
        input();
        solve();
        return 0;
    }

    练习:Codevs 1766 装果子

     在自己搭的博客用md写的: https://douzujun.github.io/page/%E7%AE%97%E6%B3%95%E7%AC%94%E8%AE%B0/STL%E5%9F%BA%E7%A1%80%20%E5%92%8C%20%E7%AE%80%E5%8D%95%E7%9A%84%E8%B4%AA%E5%BF%83%E9%97%AE%E9%A2%98.html

  • 相关阅读:
    简单手风琴特效、轮播
    MVC
    文字自动下拉隐藏显示
    jQuery基础 DOM操作
    JQuery基础
    SQL 中的常用函数及使用
    数据库中的T-sql语句 条件修改 高级查询
    2017-03-09 数据库的基本东西
    C#中的冒泡排序
    C#中的数组
  • 原文地址:https://www.cnblogs.com/douzujun/p/8079050.html
Copyright © 2011-2022 走看看