• [专题总结] 二分搜索专题


    1.1从有序数组中查找某值

        //数组长 目标值
        int n, k;
    
        int arr[n];
    
        void solve() 
        {
            sort(arr, arr + n);
    
            int fst = -1, lst = n, mid;
    
            while(lst - fst > 1)
            {
                mid = (fst + lst) / 2;
                
                if(arr[mid] >= k) //解范围(fst,mid]
                    lst = mid;
                else              //解范围(mid, lst]
                    fst = mid;
            }
    
            return lst;
            //此时 fst + 1 = lst
        }

    STL关于二分的应用

        STL
    
        lower_bound(begin, end, key)
        //从数组的begin位置到end-1位置二分查找第一个大于或等于num的数字
        //找到返回该数字的地址,不存在则返回end。
        //通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。
    
        upper_bound(begin, end, key)
        //从数组的begin位置到end-1位置二分查找第一个大于num的数字
        //找到返回该数字的地址,不存在则返回end。
        //通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。
        
        lower_bound(begin, end, num, greater<type>())
        //从数组的begin位置到end-1位置二分查找第一个小于或等于num的数字
        //找到返回该数字的地址,不存在则返回end。
        //通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。
    
        upper_bound(begin, end, num, greater<type>())
        //从数组的begin位置到end-1位置二分查找第一个小于num的数字
        //找到返回该数字的地址,不存在则返回end。
        //通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。
        
    
    
        sort(num, num + 6, cmp);                      
        //按从大到小排序
        int posa =lower_bound(num, num + 6, 7, greater<int>()) - num;  
        //返回数组中第一个小于或等于被查数的值 
        int posb =upper_bound(num, num + 6, 7, greater<int>()) - num;  
        //返回数组中第一个小于被查数的值 
    
    

    [51nod] 1001 数组中和等于K的数对

    [51nod] 1080 两个数的平方和

    [模板] 结构体使用CMP SORT 二分 的技巧 (重载) 应用51nod 四个数和为零

    1.2假定解并判断是否可行

    https://vjudge.net/problem/POJ-1064

    大意:切K段长度相同的绳子求最大长度

    C(x) = (floor(L/x))的总和是否 >= K

    double t;
    int n, k;
    double arr[MAXN];
    bool judge(double x)
    {
    	int ret = 0;
    	for(int i = 0; i < n; i++) {
    
    		ret += floor(arr[i] / x);
    	}
    	return ret >= k;
    }
    
    int main() {
    
    	scanf("%d%d", &n, &k);
    	for(int i = 0; i < n; i++) {
    
    		scanf("%lf", &arr[i]);
    	}
    	double fst = 0.0, lst = 1010101010.0, mid;
    	for(int i = 0; i < 100; i++) {
    		
    		mid = (fst + lst) / 2;
    		if(judge(mid)) 
    			fst = mid;
    		else
    			lst = mid;
    	}
    	printf("%.2f", floor(fst * 100) / 100);
        return 0;
    }

    在无法准确确定结束范围时,可按次数不断逼近 100次可达到10^-30的精度

    或使用(lst - fst) > EPS,但EPS不可太小,容易死循环。

    1.3最大值最小化

        void solve()
        {
            sort(arr, arr + n);
    
            int fst = 0, lst = INF, mid
    
            while(lst - fst > 1)
            {
                mid = (fst + lst) / 2;
                if(judge(mid))
                    fst = mid;
                else
                    lst = mid;
            }
            
            return fst;
        }

     [二分] [POJ] 2456 Aggressive cows

    [二分答案][洛谷] P1316 丢瓶盖

    复杂度大概在 O(n*logn)

    1.4最大化平均值

    现有n物的重价是W和V,选k物使得单位重量价值最大

    double wei[MAXN];
    double val[MAXN];
    double jud[MAXN];
    
    int n, m;
    
    bool cmp(double a, double b)
    {
        return a > b;
    }
    
    bool judge(double x)
    {
        for(int i = 0; i < n; i++)
            jud[i] = val[i] - x * wei[i];
    
        sort(jud, jud + n, cmp);
    
        double rs = 0;
        for(int i = 0; i < m; i++)
            rs += jud[i];
        
        return rs >= 0;
    }
    
    int main()
    {
        while(cin>>n>>m)
        {
        	for(int i = 0; i < n; i++)
            scanf("%lf%lf", &wei[i], &val[i]);
    
    	    double fst = 0.0, lst = 1010101010.0, mid;
    	    for(int i = 0; i < 100; i++) 
    	    {
    	        mid = (fst + lst) / 2.0;
    	        if(judge(mid))
    	            fst = mid;
    	        else
    	            lst = mid;
    	    }
    	    printf("%.2lf
    ", lst);
    	}
        return 0;
    }
    

    V[0]+V[1]+V[2]+...+V[n-1]             n种物品的总价值

    X * (W[0]+W[1]+W[2]+...+W[n-1]) 所猜测的单位价值为x时的总价值

    V[0] - X*W[0]

    V[1] - X*W[1]

    V[2] - X*W[2]
    ......
    排序之后取前k种最大的值相加

    (V[n-1]+V[n-2]+..V[n-k]) = S1 与 X*(W[n-1]+W[n-2]+...W[n-k]) = S2 相比较

    如果S1 >= S2 说明X的值还不够大,S1 < S2,说明X太大了
     

  • 相关阅读:
    智能问答系统构思(持续更新)
    软件测试
    Android实现智能问答机器人(四) -----连接我们的系统
    软件架构模式---分层架构V2.0
    软件架构模式---分层架构
    PHP文件上传示例
    PHP文件上传常见类型checklist
    PHP操作Mysql数据库查询数据实例
    PHP操作Mysql数据库更新数据实例
    PHP 操作Mysql数据库删除数据示例
  • 原文地址:https://www.cnblogs.com/zeolim/p/12270416.html
Copyright © 2020-2023  润新知